Java - 使用 Lambda 表达式过滤流 PlatoBlockchain 数据智能。 垂直搜索。 人工智能。

Java – 使用 Lambda 表达式过滤流

Java Streams 早在 8 年的 Java 2014 中就一直被引入,旨在将冗长的 Java 引入函数式编程范式。 Java Streams 公开了许多灵活而强大的函数式操作,以单行执行集合处理。

基于某些谓词过滤集合仍然是最常用的函数操作之一,并且可以使用 Predicate 或更简洁地说——带有 Lambda 表达式.

在这个简短的指南中,我们将了解如何使用 Lambda 表达式过滤 Java 8 流。

在 Java 中过滤流

一般来说,任何 Stream 可以通过过滤 filter() 方法和给定的谓词:

Stream filter(Predicate<? super T> predicate)

流中的每个元素都针对谓词运行,如果谓词返回,则将其添加到输出流中 true. 您可以提供一个 Predicate 实例:

Predicate contains = s -> s.contains("_deprecated");
List results = stream.filter(contains).collect(Collectors.toList());

或者,通过提供 Lambda 表达式来简化它:

List results = stream.filter(s -> s.contains("_deprecated"))
                             .collect(Collectors.toList());

甚至将 Lambda 表达式折叠成 方法参考:


List results = stream.filter(String::isEmpty)
                             .collect(Collectors.toList());

使用方法引用,您不能传递参数,但是,您可以在要过滤的对象中定义方法并将它们调整为易于过滤(只要该方法不接受参数并返回 boolean).

请记住, 流不是集合 – 它们是流 收藏品,并且您必须将它们收集回任何集合中,例如 List, Map等,以赋予它们永久性。 此外,在流元素上完成的所有操作 中间 or 终端:

  • 中间操作返回一个新流,其中包含上一个操作的更改
  • 终端操作返回数据类型,旨在结束流上的处理管道

filter() 是一个 中间 操作,并且意味着在流终止之前与其他中间操作链接。 要保留任何更改(例如对元素本身的更改或过滤结果),您必须分配结果 输出流 通过终端操作到一个新的参考变量。

请注意: 即使链接许多 lambda 表达式,您也可能不会遇到可读性问题,使用适当的换行符。

在以下示例中,我们将使用此书籍列表:

Book book1 = new Book("001", "Our Mathematical Universe", "Max Tegmark", 432, 2014);
Book book2 = new Book("002", "Life 3.0", "Max Tegmark", 280, 2017);
Book book3 = new Book("003", "Sapiens", "Yuval Noah Harari", 443, 2011);
        
List books = Arrays.asList(book1, book2, book3);

使用 Stream.filter() 过滤集合

让我们过滤这组图书。 任何谓词都可以——所以让我们例如过滤哪些书有超过 400 页:

List results = books.stream()
                          .filter(b -> b.getPageNumber() > 400)
                          .collect(Collectors.toList());

这会产生一个列表,其中包含:

[
Book{id='001', name='Our Mathematical Universe', author='Max Tegmark', pageNumber=432, publishedYear=2014}, 
Book{id='003', name='Sapiens', author='Yuval Noah Harari', pageNumber=443, publishedYear=2011}
]

过滤时,一个非常有用的链接方法是 map(),它允许您将对象映射到另一个值。 例如,我们可以将每本书映射到它的名字,因此只返回 名称 符合谓词的书籍 filter() 拨打:

List results = books.stream()
                            .filter(b -> b.getPageNumber() > 400)
                            .map(Book::getName)
                            .collect(Collectors.toList());

这会产生一个字符串列表:

[Our Mathematical Universe, Sapiens]

使用 Stream.filter() 过滤多个谓词的集合

通常,我们希望通过多个标准过滤集合。 这可以通过链接多个 filter() 电话 or 使用短路谓词,它在一个单一的条件下检查两个条件 filter() 呼叫。

 List results = books.stream()
                    .filter(b -> b.getPageNumber() > 400 && b.getName().length() > 10)
                    .collect(Collectors.toList());
                    


 List results2 = books.stream()
                    .filter(b -> b.getPageNumber() > 400)
                    .filter(b -> b.getName().length() > 10)
                    .collect(Collectors.toList());

查看我们的 Git 学习实践指南,其中包含最佳实践、行业认可的标准以及随附的备忘单。 停止谷歌搜索 Git 命令,实际上 学习 它!

当使用多个标准时——lambda 调用可能会有些冗长。 此时,将它们提取为独立的谓词可能会更清晰。 不过,哪种方法更快?

具有复杂条件的单个过滤器或多个过滤器?

这取决于您的硬件、您的集合有多大以及您是否使用并行流。 一般来说,一个条件复杂的过滤器将优于多个条件简单的过滤器(中小型集合),或者在相同级别(非常大的集合)执行。 如果您的条件太长 - 您可能会受益于将它们分布在多个 filter() 调用,以提高可读性,因为性能非常相似。

最好的选择是两者都尝试,注意性能 目标设备,并相应地调整您的策略。

GitHub用户 沃尔科达夫 在吞吐量操作/秒中进行了过滤基准测试,并将结果托管在 “javafilters 基准测试” 存储库。 结果总结在一个信息表中:

它显示在较大的集合规模下收益明显递减,两种方法的性能大致相同。 并行流在较大的集合大小时显着受益,但在较小的大小(低于约 10k 个元素)下会抑制性能。 值得注意的是,并行流比非并行流更好地保持了它们的吞吐量,这使得它们对输入的鲁棒性显着提高。

时间戳记:

更多来自 堆栈滥用