说明:
本文为牛旦教育原创,头条首发,非头条转发请注明来源和原文网址。
1.摘要
在本文中,我们将快速浏览Java 8+添加的一个主要功能——流(Streams)。
我们将通过简单的示例来解释流是什么、创建流和基本流操作等。
2. 流 API
Java 8+中的一个主要新特性是引入了流功能,在包java.util.stream中,其中包含了几个用于处理元素序列的类。
流核心API类是Stream<T>。接下来内容将演示如何使用现有的数据提供源创建流。
2.1.流创建
可以从不同的元素源来创建流,例如 借助集合或数组的stream()和of()方法的帮助
String[] arr = new String[]{"a", "b", "c"}; Stream<String> stream = Arrays.stream(arr); stream = Stream.of("a", "b", "c");
缺省的stream()方法已添加到Collection接口,且方法已做了默认实现,允许使用任何集合来作为元素源创建Stream<T>:
Stream<String> stream = list.stream();
2.2.多线程流
Stream API还通过提供parallelStream()方法简化了多线程,该方法在并行模式下对流的元素运行操作。
下面的代码允许为流的每个元素并行运行方法doWork()
list.parallelStream().forEach(element -> doWork(element));
下面将介绍一些基本的流API操作。
3.流操作
在流上可以执行许多有用的操作。
它们分为中间操作(返回Stream<T>)和终端操作(返回确定类型的结果)。中间操作允许链接。
另外,值得注意的是,对流的操作不会更改源数据。
下面是一个示例
long count = list.stream().distinct().count();
上面这个distinct() 方法表示一个中间操作,它创建前面流的唯一元素的新流。count() 方法是一个终端操作,它返回流的大小。
3.1. 迭代
Stream API 有助于替换for、for-each及 while 循环。它允许专注于操作的逻辑,但不能专注于元素序列上的迭代。例如:
for (String str : list) { if (str.contains("a")) { return true; } }
只需使用一行 Java 8+ 代码即可更改上述的代码块:
boolean isExist = list.stream().anyMatch(element -> element.contains("a"));
3.2. 过滤
filter() 方法允许我们选取满足谓词的元素流。
我们来考虑以下列表:
ArrayList<String> list = new ArrayList<>(); list.add("One"); list.add("OneAndOnly"); list.add("Derek"); list.add("Change"); list.add("factory"); list.add("justBefore"); list.add("Italy"); list.add("Italy"); list.add("Thursday"); list.add(""); list.add("");
以下代码创建了列表List<String>的Stream<String>,查找此流中包含字符"d"的所有元素,并创建一个仅包含过滤元素的新流:
Stream<String> stream = list.stream().filter(element -> element.contains("d"));
3.3. 映射
要通过向流应用特殊函数来转换流元素,并将这些新元素收集到流中,我们可以使用 map()方法,如下所示:
List<String> uris = new ArrayList<>(); uris.add("C:\\My.txt"); Stream<Path> stream = uris.stream().map(uri -> Paths.get(uri));
上述代码通过将特定的 lambda 表达式应用于初始流的每个元素,将 Stream<String> 转换为Stream<Path>。
如果流中每个元素都包含其自己的元素序列,并且想要创建这些内部元素的流,则应使用 flatMap() 方法,如下所示:
List<Detail> details = new ArrayList<>(); details.add(new Detail()); Stream<String> stream = details.stream().flatMap(detail -> detail.getParts().stream());
在此示例中,我们有一个Detail类型的元素列表。Detail类包含一个字段 PARTS,该字段是List<String>。在 flatMap() 方法的帮助下,将提取字段 PARTS 中的每个元素,并将其添加到新的结果流中。之后,初始的Stream<Detail>将被丢失。
3.4. 匹配
Stream API 提供了一组方便的工具,用于根据某些谓词验证序列的元素。为此可以使用以下方法之一:anyMatch(), allMatch(), noneMatch()。这些名字是不言自明的。下面是些返回布尔的终端操作。
boolean isValid = list.stream().anyMatch(element -> element.contains("h")); // true boolean isValidOne = list.stream().allMatch(element -> element.contains("h")); // false boolean isValidTwo = list.stream().noneMatch(element -> element.contains("h")); // false
3.5. 缩减(Reduction)
Stream API 允许借助 Stream 类型的 reduce() 方法,根据指定的函数将元素序列缩减到某个值。此方法采用两个参数:第一个,起始值。第二个,累加器函数。
注意:缩减(Reduction),是一种广泛使用的计算模型,特别是在并行计算领域。简单地来说,Reduction就是一系列的划分(Partition)和汇总(Summarize)操作的集合:对输入数据分块,对每一个分块汇总,然后再将汇总后的数据视为新的输入数据,重复分块和汇总,直到得到最终结果,可以想象为一个倒置的树。Google和Hadoop的Map/Reduce中的Reduce计算就是一个很好的例子。
假设您有一个 List<Integer>,并且想要拥有所有这些元素与某初始化整数的总和(在此示例中为 23)。那么,可以运行以下代码,结果将为 26 (23 + 1 + 1 + 1)。
List<Integer> integers = Arrays.asList(1, 1, 1); Integer reduced = integers.stream().reduce(23, (a, b) -> a + b);
3.6. 收集
缩减(Reduction)也可以由流的 collect() 方法提供。在将流转换为集合或映射,并且以单个字符串的形式表示流时,此操作非常方便。有一个实用程序类Collectors,它为几乎所有典型的收集操作提供解决方案。对于某些非常规任务,可以创建自定义收集器。
List<String> resultList = list.stream().map(element -> element.toUpperCase()).collect(Collectors.toList());
此代码使用最终端 collect() 操作将Stream<String>缩减到List<String>。
4. 总结
在本文中,我们简要地讨论了Java流--绝对是Java 8+最有趣的功能之一。
使用流还有更高级的示例,此文的目的只是提供快速和实用的介绍,引导你可以使用这些功能做点什么,并作为探索和进一步学习的起点。
后序在写写深入 Stream API 的文章和实战案例。
好叻,就写这么多了,分享出去吧 。