「这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战」
StreamAPI
Stream它专注于对数据源进行各种高效的聚合操作(aggregate operation)和大批量数据操作 (bulk data operation)。Stream API将处理的数据源看做一种Stream(流),Stream(流)在Pipeline(管道)中传输和运算,支持的运算包含筛选、排序、聚合等,当到达终点后便得到最终的处理结果。
概述:Stream关注的是对数据的运算,与CPU打交道。
-
集合关注的是数据的存储,与内存打交道
- Stream自己不会存储元素。
- Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream
- Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行
- Stream流可创建串行和并行两种模式。
-
Stream执行流程
- Stream的实例化
- 一系列的中间操作(过滤、映射、...)
- 终止操作
-
说明:
- 一个中间操作链,对数据源的数据进行处理。
- 一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用。
简单使用
1、Stream流创建方式
方式一:通过集合
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
//default Stream<E> stream():返回一个顺序流
Stream<Integer> stream = list.stream();
//default Stream<E> parallelStream():返回一个并行流
Stream<Integer> parallelStream = list.parallelStream();
方式二:通过数组
int[] arr=new int[]{1,2,3,4,5};
//调用Arrays类的static<T> Stream<T> stream(T[] array):返回一个流
IntStream stream = Arrays.stream(arr);
方式三:通过Stream的of()方法
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
方式四:创建Stream无限流
//迭代
//public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
//遍历输出前10个偶数
Stream.iterate(0,t-> t+2).limit(10).forEach(System.out::println);
2、Stream流的中间操作
搞点数据:
class BoyData{
public static List<Boy> getBoy(){
List<Boy> list=new ArrayList<>();
list.add(new Boy("aa",20));
list.add(new Boy("bb",30));
list.add(new Boy("cc",25));
list.add(new Boy("dd",23));
list.add(new Boy("ee",28));
list.add(new Boy("ee",28));
list.add(new Boy("ee",28));
return list;
}
}
看下面操作---
2.1、筛选与切片
- filter(Predicate p):接收Lambda ,从流中排除某些元素。
List<Boy> boyList = BoyData.getBoy();
//创建Stream流,以便后续操作。
Stream<Boy> boyStream = boyList.stream();
//排除年龄小于25的boy,并输出。
boyStream.filter(b->b.getAge()>25).forEach(System.out::println);
- limit(n):截断流,使其元素不超过给定数量。
//截取前2条数据并输出。
boyStream.limit(2).forEach(System.out::println);
- skip(n):跳过元素,返回一个扔掉了前n个元素的年。若流中元素不足n个,则返回一个空流。
//跳过前2条数据并输出
boyStream.skip(2).forEach(System.out::println);
- distinct():筛选,通过流所生成元素的 hashCode()和equals()去除重复元素。
//去除数据集合中的重复元素,并输出
boyStream.distinct().forEach(System.out::println);
重点:此时需要重写javaBean中的equals和hashcode方法,否则该方法失效。
重写代码:
@Override
public int hashCode() {
int result;
long temp;
result = 1;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + age;
temp = Double.doubleToLongBits(age);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(Object o) {
if(this==o){
return true;
}
if(o == null||getClass()!=o.getClass()){
return false;
}
Boy boy = (Boy) o;
if(age !=boy.age){
return false;
}
return name !=null?name.equals(boy.name):boy.name ==null;
}
2.2、排序
//自然排序
List<Integer> integers = Arrays.asList(18, 43, 66, 22, 4, 97, 12);
integers.stream().sorted().forEach(System.out::println);
//根据年龄从小到大(定制排序)
boyStream.sorted((b1,b2)->Integer.compare(b1.getAge(),b2.getAge()))
.forEach(System.out::println);
3、Stream流的终止操作
真香操作:
- allMatch(Predicate p):检查是否匹配所有元素。
-
查看所有人年龄是否都大于20
boolean allMatch = boyStream.allMatch(b -> b.getAge() > 19); System.out.println("所有人年龄是否都大于19:"+(allMatch==true?"是":"不是")); -
结果:
-
- anyMatch(Predicate p):检查是否至少匹配一个元素。
- noneMatch(Predicate p):检查是否没有匹配的元素。
- findFirst():返回第一个元素。
-
返回第一个boy
Optional<Boy> first = boyStream.findFirst(); System.out.println(first); -
结果:
-
- findAny():随机返回当前流中的任意一个元素。
- count():返回流中元素的总个数。
-
显示总共有几个boy
long count = boyStream.count(); System.out.println(count); -
结果:
-
- max(Comparator c):返回流中最大值。
-
输出最大的年龄值
Optional<Integer> maxBoy = boyStream.map(boy -> boy.getAge()).max((b1,b2)->b1.compareTo(b2)); System.out.println(maxBoy.get()); -
结果:
-
- min(Comparator c):返回流中最小值。
- forEach(Consumer c):内部迭代。
-
输出所有boy
boyStream.forEach(System.out::println); -
结果:
-
- 规约
-
reduce()——可以将流中元素反复结合起来,得到一个值并返回。
-
计算所有boy的年龄总和
Optional<Integer> sumAge = boyStream.map(boy -> boy.getAge()).reduce((b1, b2) -> b1 + b2); System.out.println(sumAge.get()); -
结果
-
- 收集
-
查找年龄小于26的boy,并存储在一个集合中返回。
List<Boy> boyList1 = boyStream.filter(boy -> boy.getAge() < 26) .collect(Collectors.toList()); boyList1.forEach(System.out::println); -
结果:
-