stream的使用 ,让我们的代码更加简洁,易懂(易维护)。它的使用,减少了大量的if条件语句和for循环语句,从输入到输出,像一条河流一样,让维护者读起来更像是读一篇文章。
一个Stream流主要由三部分组成,即数据源、中间操作、终止操作。
1、数据源
常用的创建流方式
a、Stream.of,我们可以通过Stream的静态方法,传入一个泛型数组,或者多个参数,创建一个流。
b、Arrays.stream,我们可以通过Arrays的静态方法,传入一个泛型数组,创建一个流。
c、Collection.stream,可以用过集合的接口的默认方法,创建一个流;使用这个方法,包括继承Collection的接口,如:Set,List,Map等等。
2、中间操作
常用的中间操作,以list.stream()
数据源为例
a、filter,过滤流中符合条件的元素。经过list.stream().filter(item->item>0)
的操作 ,流中只剩下大于0的item
元素。
b、map,元素类型转化。Integer
集合list
,经过list.stream().map(item->item.toString())
的操作 ,流中每个元素转化为了String
类型。
c、distinct,流中元素去重。经过list.stream().distinct()
操作,流中重复的元素被干掉。特别说明,distinct
去重依据的是hashCode
和equals
方法,如果元素是对象,若要求按照对象的某属性去重需要重写 hashCode
和equals
方法。
d、sort,流中元素排序。经过list.stream().sort()
操作,流中元素被按照自然排序。Student
对象组成的list
,若要求按照学生的年龄逆序,即list.stream().sorted(Comparator.comparing(Student::getAge).reversed())
,使用sort
排序的每个元素必须实现Comparable
接口。
e、flatMap,流的扁平化,即降维合并处理。一个List<List<String>>
流list
,经过list.stream().flatMap(item->item.stream())
的处理,变为List<String>
流。
3、终止操作
常用的终止操作,以list.stream().filter(item->item!=null)
中间操作为例
a、forEach,内部迭代。
b、allMatch, anyMatch,noneMatch 匹配,返回Boolean
类型,allMatch—检查是否匹配所有元素,anyMatch—检查是否匹配任意元素,noneMatch—检查是否没有匹配所有元素。list.stream().filter(item->item!=null).allMatch(item->item>0)
若流中元素全部大于0的返回true,否则返回false。
c、findFirst和findAny 查找,返回Optional<T>
类型。list.stream().filter(item->item!=null).findFirst()
得到T
的Optional
,若不为null
,使用get()
方法获取T
;或者orElse(null)
获取。
d、max、min和count,count()
返回元素数量 ,max()
和min()
接收一个Comparator
接口参数,返回最大和最小的Optional<T>
。 Stream.of(1, 2,3,4,5).max(Integer::compareTo)
获取元素最大的Optional<Integer>
,再使用get()
可以得到5。
补充:当max有多条记录时,取流的第1条。max用了BinaryOperator的maxBy方法。具体参照源码:
public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
Objects.requireNonNull(comparator);
return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
}
e、reduce 归约
接收一个参数:Stream.of(1,2,3,4,5).reduce((a,b)->a+b)
,结果类型为Optional<Integer>
,调用get()
方法得到15。
接收两个参数:Stream.of(1, 2, 3, 4, 5).reduce(5, (a, b) -> a + b)
,结果类型为Integer
,值为20,第一个参数为初始值 。
接收三个参数:Stream.of(1, 2, 3, 4, 5).parallel().reduce(0, (a, b) -> a + b, (s1, s2) -> s1 + s2)
,第三个参数只有在并行流中才会执行 ,作用是将并行每个流的运算结果按照第三个参数的运算规则进行最终合并。
f、collect 收集,该方法功能比较强大,能将流收集成很多形式。collect方法接收的多个参数中最主要有一个Collector
接口。
收集为List:list.stream().filter(item->item!=null).collect(Collectors.toList())
收集为Set:list.stream().filter(item->item!=null).collect(Collectors.toSet())
收集为HashSet:list.stream().filter(item->item!=null).collect(Collectors.toCollection(HashSet::new))
收集为Map,接收两个参数:list.stream().filter(item->item!=null).collect(Collectors.toMap(item1->item1.getKey(),item2->item2))
,第一个参数设置map的key,第二个参数设置map的value,此时应注意key值必须唯一,否则会抛异常。key唯一下面Guava写法效果相同:Maps.uniqueIndex(list, item->item.getKey())
,得到的结果都是Map<String,T>
类型。
接收三个参数:list.stream().filter(item->item!=null).collect(Collectors.toMap(item1->item1.getKey(),item2->item2,(val1,val2)->val2))
,前两个参数同上,第三个参数为map的value合并函数。上面表达式表示当出现相同的key时,value取后者。
接收四个参数:list.stream().filter(item->item!=null).collect(Collectors.toMap(item1->item1.getKey(),item2->item2,(val1,val2)->val2,LinkedHashMap::new))
,前三个参数同上,第四个参数表示设置接收map的容器为LinkedHashMap
。该参数不设置的情况下默认为HashMap
。
多级分组groupingBy:接收一个参数:list.stream().filter(item->item!=null).collect(Collectors.groupingBy(item1->item1.getKey()))
,按照key分组,得到Map<String,List<T>>
类型结果。
接收两个参数:list.stream().filter(item->item!=null).collect(Collectors.groupingBy(item->item.getKey(),Collectors.mapping(item->new U(item.getKey(),item),Collectors.toList())))
第二个参数重新定义了map的value收集类型,得到Map<String,List<U>>
类型结果。
上面Map<String,List<U>>
结果也可以使用toMap
实现:list.stream().filter(item->item!=null).collect(Collectors.toMap(item->item.getKey(),item -> Stream.of(new U(item.getKey(), item)).collect(Collectors.toList()),(a, b) -> Stream.concat(a.stream(), b.stream()).collect(Collectors.toList())))
//待补充…