一、概况

1.1、概念

Stream流是JDK8新增的成员,允许以声明性方式处理数据集合,可以把Stream流看作是遍历数据集合的一个高级迭代器。

1.2、stream操作的执行流程

1)、创建stream
2)、中间操作
3)、终止操作

二、执行流程

2.1、 创建stream

1、集合创建流

java.util.Collection.stream()

  1. List<String> list = new ArrayList<>();
  2. list.stream();
  3. Set<String> set = new HashSet<>();
  4. set.stream();
  5. Map<String,String> map = new HashMap<>();
  6. map.keySet().stream();
  7. map.values().stream();
  8. map.entrySet().stream();

2、数组创建流

java.util.Arrays.stream(T[] array)

  1. String[] arr = {};
  2. Arrays.stream(arr);

3、Stream的静态方法

Stream.of(T t)
Stream.of(T… values)
Stream.iterate(T seed,UnaryOperator f):生成一个无限长度的Stream,参数一是初始值,参数二是函数,作用于参数一。一般与limit连用,限制元素个数。
Stream.generate(Supplier s):生成一个无限长度的Stream,一般与limit连用。常用场景:生成常量流和随机数流。
Stream.of(1);
Stream.of(1,2,3);
Stream.iterate(0,(e->e+1)).limit(5).forEach(e-> System.out.println(e));
Stream.generate(()->Math.random()).limit(5).forEach(e-> System.out.println(e));

2.2、中间操作

1、概念

每次返回一个新的流,可以有多个

2、分类

1)、无状态(元素处理不受之前元素影响)

filter()、map()、mapToInt()、mapToLong()、mapToDouble()、flatMap()、flatMapToInt()、flatMapToLong()、flatMapToDouble()、peek()、unordered()

2)、有状态(必须拿到全部元素才能继续下去)

distinct()、sorted()、limit()、skip()

3、详细介绍

1)、filter()

对流中的元素按照给定的函数过滤,生成新的符合过滤条件的流。

  1. Integer[] arr = {1,2,3,4,5,6,7,8,9,10};
  2. Stream.of(arr).filter(e->e>=5).forEach(e-> System.out.println(e));
  3. //输出:
  4. 5
  5. 6
  6. 7
  7. 8
  8. 9
  9. 10

2)、map()

对流中的每个元素按照给定的函数进行转换操作,生成新的流只包含转换后的元素。
String[] arr = {“apple”,”banana”,”orange”};
Stream.of(arr).map(e ->e.length()).forEach(e->System.out.println(e));

//输出:
5
6
6
mapToInt()、mapToLong()、mapToDouble()是map()的是三个变种方法,主要作用是免除自动拆箱装箱的额外消耗。

3)、flatMap()

对流中的每个元素进行扁平化提取,组成新的流。
map()与flatMap()对比:map提取流中的引用组成新的流,而flatMap提取流中的元素组成新的流。

  1. String[] arr = {"1-2-3-4","5-6-7"};
  2. Stream.of(arr).map(e->Stream.of(e.split("-"))).forEach(e-> System.out.println(e));
  3. Stream.of(arr).flatMap(e->Stream.of(e.split("-"))).forEach(e-> System.out.println(e));
  4. List<List<String>> lists = new ArrayList<>();
  5. List<String> list1 = Arrays.asList("a","b","c");
  6. List<String> list2 = Arrays.asList("d","e","f");
  7. lists.add(list1);
  8. lists.add(list2);
  9. lists.stream().flatMap(e->e.stream()).forEach(e-> System.out.println(e));
  10. //输出:
  11. java.util.stream.ReferencePipeline$Head@5680a178
  12. java.util.stream.ReferencePipeline$Head@5fdef03a
  13. 1
  14. 2
  15. 3
  16. 4
  17. 5
  18. 6
  19. 7
  20. a
  21. b
  22. c
  23. d
  24. e
  25. f

flatMapToInt()、flatMapToLong()、flatMapToDouble()是flatMap()的是三个变种方法,主要作用是免除自动拆箱装箱的额外消耗。

  1. String[] arr = {"1","2","3","4","5","6"};
  2. Stream.of(arr).flatMapToDouble(e-> DoubleStream.of(Double.parseDouble(e))).forEach(e-> System.out.println("value:"+e+",type:"+ToolUtil.getType(e)));
  3. //输出:
  4. value1.0typeclass java.lang.Double
  5. value2.0typeclass java.lang.Double
  6. value3.0typeclass java.lang.Double
  7. value4.0typeclass java.lang.Double
  8. value5.0typeclass java.lang.Double
  9. value6.0typeclass java.lang.Double

4)、peek()

将流中的元素进行消费,不改变流中的元素。
peek()与map()的区别:map操作可以改变流中的元素,有返回值;peek操作仅仅在操作中消费元素,没有返回值,传入下一个操作的元素不会改变。

  1. String[] arr = {"1","2","3","4","5","6"};
  2. Stream.of(arr).map(e-> {
  3. e = e + "a";
  4. System.out.println("map:"+e);
  5. return e;
  6. }).forEach(e-> System.out.println("map-foreach:"+e));
  7. Stream.of(arr).peek(e-> {
  8. e = e + "a";
  9. System.out.println("peek:"+e);
  10. }).forEach(e-> System.out.println("peek-foreach:"+e));
  11. //输出:
  12. map:1a
  13. map-foreach:1a
  14. map:2a
  15. map-foreach:2a
  16. map:3a
  17. map-foreach:3a
  18. map:4a
  19. map-foreach:4a
  20. map:5a
  21. map-foreach:5a
  22. map:6a
  23. map-foreach:6a
  24. peek:1a
  25. peek-foreach:1
  26. peek:2a
  27. peek-foreach:2
  28. peek:3a
  29. peek-foreach:3
  30. peek:4a
  31. peek-foreach:4
  32. peek:5a
  33. peek-foreach:5
  34. peek:6a
  35. peek-foreach:6

5)、unordered()

基于调用流,返回一个无序流。
在有序流的并行执行情况下,保持 的顺序性是需要高昂的缓冲开销。所以在处理元素时,不需要保证元素的顺序性,那么我们可以使用 unordered() 方法来实现无序流。

6)、distinct()

将流中的元素去重。如果是自定义类,一定要重写equals()方法与hashCode()方法。

7)、sorted()

默认按自然升序对集合进行排序,可使用Comparator提供 reverseOrder() 方法实现降序排列。

  1. String[] arr = {"7","2","0","4","2","6"};
  2. Stream.of(arr).sorted().forEach(e-> System.out.print(e+"->"));
  3. System.out.println();
  4. Stream.of(arr).sorted(Comparator.reverseOrder()).forEach(e-> System.out.print(e+"->"));
  5. System.out.println();
  6. Stream.of(arr).sorted(new Comparator<String>() {
  7. @Override
  8. public int compare(String o1, String o2) {
  9. return o2.compareTo(o1);
  10. }
  11. }).forEach(e-> System.out.print(e+"->"));
  12. //输出:
  13. 0->2->2->4->6->7->
  14. 7->6->4->2->2->0->
  15. 7->6->4->2->2->0->

8)、limit()

截取前n个元素,返回新的stream流。

9)、skip()

跳过前面n个元素,返回新的stream流。

2.3、终止操作

1、概念

每个流只能进行一次终止操作,终止操作结束后流无法再使用。终端操作会产生新的集合或者值。

2、分类

1)、非短路操作(必须处理完所有操作才能得到结果)

forEach()、forEachOrdered()、toArray()、reduce()、collect()、max()、min()、count()

2)、短路操作(遇到符合条件的元素就可以得到最终结果)

anyMatch()、allMatch()、noneMatch()、findFirst()、findAny()

3、详细介绍

1)、forEach()

遍历。在并行操作中,这种方法不能保证按顺序执行。

2)、forEachOrdered()

遍历。保证了在顺序流和并行流中都按顺序执行。

3)、toArray()

将流转为数组。

4)、reduce()

是一个规约操作,所有的元素归约成一个结果值。三种调用方法,如下:
1. Optional reduce(BinaryOperator accumulator):一个参数,这个参数的名称accumulator(累加器),它的类型是一个函数式接口,这个接口是继承了BiFunction,实现这个接口有两个输入,一个T类型,一个U类型,返回值是R类型。
2. T reduce(T identity, BinaryOperator accumulator):两个参数。第一个参数是初始值(限制必须是流元素类型),第二个参数跟方法一中参数一致。
3. U reduce(U identity, BiFunction accumulator, BinaryOperator combiner):三个参数。前两个参数是对方法二的改进,此方法可以自定义初始值和返回值的类型。第三个参数用来合并并行流,也就是说只有使用了并行流,第三个参数才有意义。

  1. String[] arr = {"1","2","3","4","5","6"};
  2. Optional<String> result1 = Stream.of(arr).reduce((e1, e2)->e1+e2);
  3. String result2 = Stream.of(arr).reduce("",(e1,e2)->e1+e2);
  4. Integer result3 = Stream.of(arr).reduce(0,(e1,e2)->Integer.valueOf(e1)+Integer.valueOf(e2),(arr1,arr2)->Integer.valueOf(arr1)+Integer.valueOf(arr2));
  5. System.out.println(result1);
  6. System.out.println(result2);
  7. System.out.println(result3);
  8. //输出:
  9. Optional[123456]
  10. 123456
  11. 21

5)、collect()

收集。
1、 R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner);
2、 R collect(Collector<? super T, A, R> collector);
3、stream.collect(Collectors.toList())
4、stream.collect(Collectors.toSet())
5、stream.collect(Collectors.toCollection(Supplier collectionFactory))
6、stream.collect(Collectors.joining())

6)、max()

取最大值

  1. String[] arr = {"apple","banana","waltermaleon"};
  2. System.out.println(Stream.of(arr).max((e1,e2)-> {
  3. return e1.length() - e2.length();
  4. }).get());

//输出:
waltermaleon

7)、min()

取最小值

  1. String[] arr = {"apple","banana","waltermaleon"};
  2. System.out.println(Stream.of(arr).min((e1,e2)-> {
  3. return e1.length() - e2.length();
  4. }).get());

//输出:
apple

8)、count()

取流中元素的个数。

  1. String[] arr = {"7","2","0","4","2","6"};
  2. 6
  3. System.out.println(Stream.of(arr).count());
  4. //输出:

9)、anyMatch()

任意匹配。对流中的元素进行判断,有任意一个匹配,则返回ture。否则返回false。
allMatch():完全匹配。对流中所有的元素进行判断,如果都满足返回true,否则返回false。
noneMatch():不匹配。判断数据流中没有一个元素与条件匹配的,返回true,否则返回false。

  1. String[] arr = {"banana","peach","apple","orange", "waltermaleon", "grape"};
  2. System.out.println(Stream.of(arr).anyMatch(e->e.equals("apple"));

10)、findFirst()

获取流中的第一个元素。
findAny():获取流中任意一个元素,搭配parallel使用,才会生效。

  1. String[] arr = {"banana","peach","apple","orange", "waltermaleon", "grape"};
  2. Stream.of(arr).filter(e->e.length() == 5).parallel().findFirst().ifPresent(e-> System.out.println(e));

//输出:
peach