Java8特性学习笔记(四) Stream

2021-12-29  本文已影响0人  简单一点点

参考:

简介

java.util.Stream 表示能应用在一组元素上一次执行的操作序列。Stream 操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回 Stream 本身,这样你就可以将多个操作依次串起来。Stream 的创建需要指定一个数据源,比如 java.util.Collection 的子类,List 或者 Set, Map 不支持。Stream 的操作可以串行执行或者并行执行。

它具有如下特点:

Stream 的创建

最常用的方式是通过 Collection.stream() 或者 Collection.parallelStream() 来创建一个 Stream。

List<String> list = new ArrayList<>();
Stream<String> stream = list.stream(); // 创建顺序流
Stream<String> parallelStream = list.parallelStream(); // 创建并行流

使用 Arrays 中的 stream() 方法,可以将数组转成流。

Integer[] nums1 = new Integer[10]; // 注意使用Integer数组
Stream<Integer> stream = Arrays.stream(nums1);
int[] nums = new int[10]; // int数组只能生成 IntStream流
IntStream iantStrem = Arrays.stream(nums);

使用Stream中的静态方法:of()iterate()generate()

Stream<Integer> stream = Stream.of(1, 2, 3);
stream.forEach(System.out::println);

Stream<Integer> stream2 = Stream.iterate(0, x -> x + 2).limit(5); // limit 限制数量
stream2.forEach(System.out::println);

Stream<Integer> stream3 = Stream.generate(new Random()::nextInt).limit(5); // limit 限制数量
stream3.forEach(System.out::println);

使用 BufferedReader.lines() 方法,将每行内容转成流。

BufferedReader reader = new BufferedReader(new FileReader("a.txt"));
Stream<String> stream = reader.lines();
stream.forEach(System.out::println);

使用 Pattern.splitAsStream() 方法,将字符串分隔成流。

Pattern pattern = Pattern.compile(",");
Stream<String> stream = pattern.splitAsStream("a,bb,f,gh");
stream.forEach(System.out::println);

Stream方法分类

Stream方法可以分为中间操作(Intermediate Operations)和结束操作(Terminal Operations)。中间操作会返回新的Stream供后续操作,而结束操作会返回最终结果。

中间操作可以分析有状态(只有拿到所有元素之后才能继续)和无状态(元素处理不受之前影响)两类。

无状态操作包括:

有状态操作包括:

结束操作可以分为非短路操作(必须处理所有元素才能得到最终结果)和短路操作(遇到某些符合条件的元素即可得到最终结果)。

非短路操作保护:

短路操作包括:

Stream 常用方法

本部分重点介绍一下 Stream 常用方法。

为了方便测试,先写个例子。

List<String> stringList = new ArrayList<>();
stringList.add("asc");
stringList.add("fff");
stringList.add("sxcfg");
stringList.add("ds");
stringList.add("aaa3");

filter

过滤通过一个 predicate 接口来过滤并只保留符合条件的元素,该操作属于中间操作,所以我们可以在过滤后的结果来应用其他Stream操作(比如forEach)。

stringList.stream().filter(s -> s.startsWith("a")).forEach(System.out::println);

sorted

排序是一个中间操作,返回的是排序好后的 Stream。如果你不指定一个自定义的 Comparator 则会使用默认排序。

stringList.stream().sorted().forEach(System.out::println);

需要注意的是,排序只创建了一个排列好后的Stream,而不会影响原有的数据源,如我们之前所说,Stream 一般不会修改数据源。

map

中间操作 map 会将元素根据指定的 Function 接口来依次将元素转成另外的对象。

stringList.stream().map(String::toUpperCase).forEach(System.out::println);

match

Stream 提供了多种匹配操作,允许检测指定的Predicate是否匹配整个Stream。所有的匹配操作都是最终操作 ,并返回一个 boolean 类型的值。

boolean anyStartsWithA = stringList.stream().anyMatch((s) -> s.startsWith("a")); // true
boolean allStartsWithA = stringList.stream().allMatch((s) -> s.startsWith("a")); // false
boolean nonStartsWithZ = stringList.stream().noneMatch((s) -> s.startsWith("z")); // true

count

计数是一个最终操作,返回 Stream 中元素的个数,需要注意返回值类型是 long

long countStartsWithA = stringList.stream().filter((s) -> s.startsWith("a")).count();

这是一个最终操作 ,允许通过指定的函数来将stream中的多个元素规约为一个元素,规约后的结果是通过Optional 接口表示的。

Optional<String> reduced = stringList.stream()
                                .sorted()
                                .reduce((s1, s2) -> (s1 + "#" + s2));
reduced.ifPresent(System.out::println);

一般来说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce。例如 Stream 的 sum 就相当于Integer sum = integers.reduce(0, (a, b) -> a+b);,也有没有起始值的情况,这时会把 Stream 的前面两个元素组合起来,返回的是 Optional。

Parallel Stream

Stream有串行和并行两种,串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。

并行Stream效率较高,但是不保证顺序。

IntStream、LongStream和DoubleStream

这三者分别是int、long和double类型的流,其实有很多和Stream类似的地方。

具体暂时先不展开介绍了。

上一篇 下一篇

猜你喜欢

热点阅读