Stream流
1. 简介
- 特点:
- 流不会储存元素,所以每个Stream流只能使用一次(每次调用方法后都会销毁)
- 流不会修改其数据源,只是在原数据集上定义了一组操作。
- 流执行具有延迟特性,即每当访问到流中的一个元素,才会在此元素上执行这一系列操作。
- 流操作:
- 生成流
- 中间操作(原Stream流销毁,返回一个新流)
- 终结操作(最终操作,不会返回新流)
2.方法简介
方法 | 描述 |
---|---|
流的生成方法 | |
of() | 静态方法,返回一个包含参数的流,有两个overload方法,一个接受变长参数,一个接受单一值 |
generator() | 静态方法,返回一个无限长的流,其元素生成是通过循环调用参数Suppier,配合limit()使用 |
iterator() | 静态方法,传入一个Seed和一个函数,循环嵌套将seed嵌入函数返回新seed并存入流中,配合limit()使用 |
concat() | 静态方法,传入两个流,拼接成一个新流返回 |
中间操作 | |
filter() | 接受一个 Predicate 参数,判断流中符合条件的元素,并封装成新流返回 |
map() | 对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。 |
flatMap() | 和map类似,不同的是其每个元素转换得到的是Stream对象,会把子Stream中的元素压缩到父集合中 |
limit() | 截取原Stream流中的前N个元素(小于N则截取原来所有元素),并返回新流 |
skip() | 跳过原Stream流的前N个元素,截取剩下的所有元素(如果N大于原流长度则获取一个空Stream),返回新流 |
distinct() | 去除流中的重复元素,封装成新流返回 |
sorted() | 按默认方式给流中元素排序后封装成新流返回 |
sorted(Comparable) | 将流中元素按指定排序方式排序返回 |
peek() | 生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数(Consumer实例),新Stream每个元素被消费的时候都会执行给定的消费函数 |
终结操作 | |
count() | 返回此流中的元素数 |
forEach() | 遍历流中元素,执行指定操作 |
collect(Collector) | 传入指定容器,将流中元素存入到指定的容器之中返回 |
3.方法详解
-
流生成方法:
-
Collection接口的stream()或parallelStream()方法
ArrayList<String> arr = new ArrayList<>(); arr.stream();
-
静态的Stream.of()、Stream.empty()方法
Stream.of("one","two","three") //创建一个空的流 Stream.empty()
-
Arrays.stream():
// 传入一个数组 Arrays.stream(new int[]{1,2,3}) // 传入一个数组和截取索引(startIndex不为负数,endIndex小于数组大小,大于startIndex) Arrays.stream({1,2,3,4,5,6,7,8,9,10},1,10) //截取后流(2,3,4,5,6,7,8,9,10)
-
Stream.iterate()方法生成无限流,接受一个种子值以及一个迭代函数
// 需配合limit使用,不然回无限延伸 Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4); // 流中元素(0,3,6,9)
-
Stream.generate()
// 传入一个函数,循环调用生成流中元素,不然流会无限延伸 Stream.generate(Math::random).limit(5)
-
Stream.concat()方法将两个流连接起来
Stream.concat(stream1,stream2)
-
-
流的中间操作
-
filter(Predicate)
// 传入一个Predicate,过滤其中判断为false的元素 ArrayList<String> arr = new ArrayList<>(); arr.add("Ye"); arr.add("Song"); arr.add("Tong") arr.stream().filter(s -> s.size() > 2).forEach(System.out::println) // 输出结果(过滤不满足长度大于2的"Ye") "Song" "Tong"
-
map(fun)
// 转换元素的值,可以用方法引用或者lambda表达式 ArrayList<String> arr = new ArrayList<>(); arr.add("Ye"); arr.add("Song"); arr.add("Tong") arr.stream.map(s -> s.toUpperCase).forEach(System.out::println) // 转换后输出结果 "YE" "SONG" "TONG"
-
flatMap(fun)
// 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。(平摊所有元素中子元素) List<String> list = Arrays.asList("m,k,l,a", "1,3,5,7"); List<String> listNew = list.stream().flatMap(s -> { // 将每个元素转换成一个stream String[] split = s.split(","); Stream<String> s2 = Arrays.stream(split); return s2; }).collect(Collectors.toList()); System.out.println("处理后的集合:" + listNew); // 输出结果 处理后的集合:[m, k, l, a, 1, 3, 5]
-
limit(n)
// 保留前N个元素 stream.limit(4)
-
skip(n)
// 跳过前N个元素 stream.skip(4)
-
distinct()
// 剔除重复元素 ArrayList<String> arr = new ArrayList<>(); arr.add("Ye"); arr.add("Ye"); arr.add("Ye"); arr.add("Song"); arr.add("Tong") arr.stream().distinct().forEach(System.out::println) // 输出结果 "YE" "SONG" "TONG"
-
sorted()
// 按默认方式重载 Arrays.stream(new int[]{4,5,6,8,3,1,2}).sort().forEach(System.out::println) //输出结果 1 2 3 4 5 6 8 // 传入Comparator,按指定方式排序 List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Sherry", 9000, 24, "female", "New York")); personList.add(new Person("Tom", 8900, 22, "male", "Washington")); personList.add(new Person("Jack", 9000, 25, "male", "Washington")); personList.add(new Person("Lily", 8800, 26, "male", "New York")); personList.add(new Person("Alisa", 9000, 26, "female", "New York")); List<String> newList = personList.stream().sorted(Comparator.comparing(Person::getSalary)).map(Person::getName) .collect(Collectors.toList()); System.out.println("按工资升序排序:" + newList); // 输出结果 按工资升序排序:[Lily, Tom, Sherry, Jack, Alisa]
-
peek(fun)
// peek的意思是偷看,查看,传入Consumer接口,不消耗对象。流不变,但会把每个元素传入fun执行,可以用作调试 Stream.of("one", "two", "three", "four") .filter(e -> e.length() > 3) .peek(e -> System.out.println("Filtered value: " + e)) .map(String::toUpperCase) .peek(e -> System.out.println("Mapped value: " + e)) .forEach(System.out::println)
-
-
流的终结操作
-
max() / min()
// 传入comparator, 获取最大或最小值,封装成Optional返回 List<String> list = Arrays.asList("adnm", "admmt", "pot", "xbangd", "weoujgsd"); Optional<String> max = list.stream().max(Comparator.comparing(String::length)); System.out.println("最长的字符串:" + max.get());
-
count()
// 返回流中元素个数 stream.count()
-
collect
//因为流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toList、toSet和toMap比较常用,另外还有toCollection、toConcurrentMap等复杂一些的用法。 List<Integer> list = Arrays.asList(1, 6, 3, 4, 6, 7, 9, 6, 20); List<Integer> listNew = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
-
4. 总结
Stream对于我们对集合和数组的处理起到了非常大的帮助,由于内部是通过多线程并行的方式处理数据所以效率比遍历更高,但是在数据量少的时候由于需要消耗时间和资源启动线程所以效率不如遍历,更加适合大数据量的处理。在本文中还有很多Stream的方法由于在工作中比较少使用所以没有介绍,待笔者技能提升之后会作后续的更新补充。