一、 Stream 操作的三个步骤
- 创建 Stream
一个数据源(如: 集合、数组), 获取一个流。
- 中间操作
一个中间操作链,对数据源的数据进行处理。
- 终止操作
一个终止操作,执行中间操作链,并产生结果。
二、如何创建Stream
Java8 中的 Collection 接口被扩展,提供了两个获取流的方法
获取一个串行流
defaultStream<E>stream() { returnStreamSupport.stream(spliterator(), false); }
获取一个并行流
defaultStream<E>parallelStream() { returnStreamSupport.stream(spliterator(), true); }
Java8 中的 Arrays 的静态方法 stream() 可以获取数组流
publicstatic<T>Stream<T>stream(T[] array) { returnstream(array, 0, array.length); }
通过 Stream 类的静态方法 of()获取数组流
publicstatic<T>Stream<T>of(Tt) { returnStreamSupport.stream(newStreams.StreamBuilderImpl<>(t), false); }
三、Stream中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会 执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值",Stream 的中间操作是不 会有任何结果数据输出的。
Stream 的中间操作在整体上可以分为:筛选与切片、映射、排序。
(一)筛选与切片
1.筛选filter
filter(Predicate p) 接收 Lambda 表达式,从流中排除某些元素
protectedList<Employee>list=Arrays.asList( newEmployee("Lisa", 18, 9999.99), newEmployee("Ruby", 38, 5555.55), newEmployee("Charles", 60, 6666.66), newEmployee("Vincent", 28, 8888.77), newEmployee("Quella", 58, 4444.33) ); publicvoidtestFilter() { Stream<Employee>list2=list.stream().filter(x->x.getAge() >30 ); }
2.limit()
主要作用为:截断流,使其元素不超过给定数量
list.stream().filter((e) ->e.getAge() >30 ).limit(2).forEach(System.out :: println);
3.skip()
跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素 不足 n 个,则返回一个空流。与 limit(n) 互补。
list.stream().skip(2).forEach(System.out :: println
4.distinct()
去重操作,通过流所生成元素的 hashCode() 和 equals() 去 除重复元素,distinct 需要实体中重写 hashCode()和 equals()方法才 可以使用
list.stream().distinct().forEach(System.out :: println);
(二)映射
1.map
接收一个函数作为参数,该函数会被应用到每个元 素上,并将其映射成一个新的元素。
方法声明
<R>Stream<R>map(Function<?superT, ?extendsR>mapper)
比如把以下集合元素全部转化为大写,然后再输出
List<String>list=Arrays.asList("a", "b", "c", "d"); list.stream().map((e) ->e.toUpperCase()).forEach(System.out::printf)
2.flatMap
接收一个函数作为参数,将流中的每个值都换成另 一个流,然后把所有流连接成一个流。
publicvoidtestFlatMap(){ List<Data2>listOfData2=Arrays.asList( newData2(10501, "JOE" , "Type1"), newData2(10603, "SAL" , "Type5"), newData2(40514, "PETER", "Type4"), newData2(59562, "JIM" , "Type2"), newData2(29415, "BOB" , "Type1"), newData2(61812, "JOE" , "Type9"), newData2(98432, "JOE" , "Type7"), newData2(62556, "JEFF" , "Type1"), newData2(10599, "TOM" , "Type4") ); List<Data1>listOfData1=Arrays.asList( newData1(10501, "JOE" ,3000000), newData1(10603, "SAL" ,6225000), newData1(40514, "PETER" ,2005000), newData1(59562, "JIM" ,3000000), newData1(29415, "BOB" ,3000000) ); List<OutputData>result=listOfData1.stream() .flatMap(x->listOfData2.stream() .filter(y->x.getId() ==y.getId()) .map(y->newOutputData(y.getId(), x.getName(), y.getType(), x.getAmount()))) .collect(Collectors.toList()); System.out.println(result); }
(三)排序
1.sorted()
产生一个新流,其中按自然顺序排序
List<Employee>persons=list.stream().sorted().collect(Collectors.toList());
2.sorted(Comparator comp)
产生一个新流,其中按自定义的比较器顺序排序
List<Employee>persons1=list.stream().sorted((e1, e2) -> { if (e1.getAge() ==e2.getAge()) { return0; } elseif (e1.getAge() >e2.getAge()) { return1; } else { return-1; } }).collect(Collectors.toList());
四、终止操作
终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如: List、 Integer、 Double、String 、甚至是void
1.allMatch(Predicate p)
检查是否匹配所有元素,只有所有的元素都匹配条件时,allMatch()方法才会返回 true
booleanmatch=employees.stream().allMatch((e) ->Employee.Stauts.SLEEPING.equals(e.getStauts()));
2.anyMatch()
使用 anyMatch()方法时,只要有任意一个元素符合条件,anyMatch()方法就会返回 true
booleanmatch=employees.stream().anyMatch((e) ->Employee.Stauts.SLEEPING.equals(e.getStauts()))
3.findFirst()
findFirst()方法表示返回流中的第一个元素。
Optional<Employee>op=employees.stream().sorted((e1, e2) ->Double.compare(e1.getSalary(), e2.getSalary())).findFirst();
4.count()
count()方法表示返回流中元素总数。
longcount=employees.stream().count();
5.forEach()
forEach()方法表示内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反, Stream API 使用内部迭代)。其在 Stream 接口内部的定义如下所示。
voidforEach(Consumer<?superT>action); employees.stream().forEach(System.out::println);
五、Reduce
reduce()是把流中所有元素结合起来,生成一个新的值。reduce()方法在 Stream 接口中的定义如下所示
Treduce(Tidentity, BinaryOperator<T>accumulator); Optional<T>reduce(BinaryOperator<T>accumulator); <U>Ureduce(Uidentity, BiFunction<U, ?superT, U>accumulator, BinaryOperator<U>combiner);
List<Integer>list=Arrays.asList(1,2,3,4,5,6,7,8,9,10); Integersum=list.stream().reduce(0, (x, y) ->x+y); System.out.println(sum);
六、收集
collect(Collector c) 将流转换为其他形式。接收一个 Collector 接口的实现,用于给 Stream 中元 素做汇总的方法
Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例, 具体方法与实例如下表:
方法 |
返回值 |
方法作用 |
使用示例 |
toList | List |
List 把流中元素收集到 List |
List employees= list.stream().collect(Collectors.toList()); |
toSet |
Set |
把流中元素收集到 Set |
Set employees= list.stream().collect(Collectors.toSet()); |
toCollection |
Collection |
把流中元素收集到创建的集合 |
Collection employees=list.stream().collect(Collectors.toCollection(Arra yList::new)); |
counting |
Long |
计算流中元素的个数 |
long count = list.stream().collect(Collectors.counting()); |
joining |
String |
连接流中每个字符串 |
String str= list.stream().map(Employee::getName).collect(Collectors.jo ining()); |
maxBy |
Optional |
根据比较器选择最大值 |
Optionalmax= list.stream().collect(Collectors.maxBy(comparingInt(Em ployee::getSalary))); |
minBy |
Optional |
根据比较器选择最小值 |
Optional min = list.stream().collect(Collectors.minBy(comparingInt(E mployee::getSalary))); |
reducing |
归约产生的类型 |
从一个作为累加器的初始值 开始,利用 BinaryO perator 与 流中元素逐个结合,从而归 约成单个 值 |
int total=list.stream().collect(Collectors.reducing(0, Employee::getSala r, Integer::sum)); |
groupingBy |
Map<K,List> |
根据某属性值对流分组,属 性为 K,结果为 |
Map map= list.stream() .collect(Collectors.groupin gBy(Employee::getStatus)); |