java8关于stream操作api总结:
一、先介绍几个名词:
1、中间操作:
中间操作会产生另一个流。因此中间操作可以用来创建执行一系列动作的管道。一个特别需要注意的点是:中间操作不是立即发生的。相反,当在中间操作创建的新流上执行完终端操作后,中间操作指定的操作才会发生
2、终止操作:
会消费流,这种操作会产生一个结果的,如果一个流被消费过了,那它就不能被重用的。
3、"中间操作"的状态:
(1)无状态操作:在处理流中的每个元素时,与其他元素无关
(2)有状态操作:在处理流中的每个元素时,依赖其他元素(eg:min,max之类的)
4、缩减操作:
把一个流经过一个操作,输出一个值。eg:min、max,或者典型的reduce操作
5、for&forEach:
我们在访问一个数组元素的时候,最快的方式肯定是通过索引去访问的吧,而for循环遍历的时候就是通过下标进行的,所以效率那是相当的高,但是当我们的数据结构不是数组的时候,比如是链表的时候,可想而知,for循环的效率是有多低,但是forEach底层采用的是迭代器的方式,他对数据结构是没有要求的,不管上层的数据结构是什么,他都能保证高效地执行!因此我的最终答案:如果数据结构是ArrayList这种数据结构,那你可以采用for,但是你的数据结构如果是LinkList那你千万别再用for,应该果断采用forEach。
6、并行流:
调用parallel()就可以获取到一个并行流了,帮助我们多线程操作,提高效。需要注意的是,服务器需要多核支持
for循环,stream操作,并行stream操作的性能对比:
并行stream > for > stream : 数据量不大或者核数不够多的情况下,for比并行stream效率高
二、各种api:
1、中间操作——筛选
方法 |
描述 |
filter(Predicate p) |
接收 Lambda , 从流中排除某些元素。 |
distinct() |
筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素 |
limit(long maxSize) |
截断流,使其元素不超过给定数量。 |
skip(long n) |
跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补 |
2、中间操作——映射
方法 |
描述 |
map(Function f) |
接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。 |
mapToDouble(ToDoubleFunction ) |
接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。 |
mapToInt(ToIntFunction ) |
接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。 |
mapToLong(ToLongFunction ) |
接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。 |
flatMap(Function f) |
接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 |
3、中间操作——排序
方法 |
描述 |
sorted() |
产生一个新流,其中按自然顺序排序 |
sorted(Comparator comp) |
产生一个新流,其中按比较器顺序排序 |
4、终止操作——查找与匹配
方法 |
描述 |
allMatch(Predicate p) |
检查是否匹配所有元素 |
anyMatch(Predicate ) |
检查是否至少匹配一个元素 |
noneMatch(Predicate p) |
检查是否没有匹配所有元素 |
findFirst() |
返回第一个元素 |
findAny() |
返回当前流中的任意元素 |
count() |
返回流中元素总数 |
max(Comparator c) |
返回流中最大值 |
min(Comparator c) |
返回流中最小值 |
forEach(Consumer c) |
stream API 使用内部迭代(默认做了外部迭代) |
5、终止操作——归约
方法 |
描述 |
reduce(T identity, BinaryOperator b) |
可以将流中元素反复结合起来,得到一个值。返回 T。<br />在第一个版本当中,identity是这样一个值,对于涉及identity和流中任意的累积操作,得到的结果就是元素自身,没有任何改变。比如,如果是加法,他就是0,如果是乘法他就是1。 |
reduce(BinaryOperator b) |
可以将流中元素反复结合起来,得到一个值。返回 Optional |
@Test
public void reduceParallel() {
List<Integer> lists = new ArrayList<>();
lists.add(1);
lists.add(2);
lists.add(3);
//每个元素都放大两倍后,再求积
Integer product = lists.parallelStream().reduce(1, (a, b) -> a * (b * 2),
(a, b) -> a * b);
System.out.println("product:" + product);//48
Integer product2 = lists.parallelStream().reduce(1, (a, b) -> {
System.out.println("第一个参数:" + Thread.currentThread().getName() +",a="+a+",b="+b);
return a * (b * 2);},
(a, b) -> {
System.out.println("第二个参数:" + Thread.currentThread().getName()+",c="+a+",d="+b);
return a * b;
});
System.out.println("product2:" + product);//48
}
6、终止操作——收集,注意这里返回的都是一个收集器Collector
方法 |
描述 |
collect(Collector c) |
将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法 |
三、关于各种收集器:
1、均值——averaging
方法 |
描述 |
averagingInt(ToIntFunction<? super T> mapper) |
接收一个函数作为参数,求该函数的返回值(int)的均值 |
averagingLong(ToLongFunction<? super T> mapper) |
接收一个函数作为参数,求该函数的返回值(long)的均值 |
averagingDouble(ToDoubleFunction<? super T> mapper) |
接收一个函数作为参数,求该函数的返回值(double)的均值 |
@Test
public void testAveraging() {
List<Integer> lists = new ArrayList<>();
lists.add(1);
lists.add(2);
lists.add(3);
Double average = lists.stream().collect(Collectors.averagingInt(item -> item));
System.out.println(average);
}
2、统计——元素个数:counting
方法 |
描述 |
counting() |
统计输入元素的个数 |
@Test
public void testCounting() {
List<Integer> lists = new ArrayList<>();
lists.add(1);
lists.add(2);
lists.add(3);
Long count = lists.stream().collect(Collectors.counting());
System.out.println(count);
}
3、最值——maxBy、minBy
方法 |
描述 |
minBy(Comparator<? super T> comparator) |
接收一个比较器,返回最小值 |
maxBy(Comparator<? super T> comparator) |
接收一个比较器,返回最大值 |
@Test
public void testMax() {
List<Integer> lists = new ArrayList<>();
lists.add(1);
lists.add(2);
lists.add(3);
Optional<Integer> max = lists.stream().collect(Collectors.maxBy(Integer::compare));
if (max.isPresent()){
System.out.println(max.get());
}
}
4、求和——summing、summarizing
方法 |
描述 |
summingInt(ToIntFunction<? super T> mapper) |
可以计算输入元素的总和 |
summingLong(ToLongFunction<? super T> mapper) |
可以计算输入元素的总和 |
summingDouble(ToDoubleFunction<? super T> mapper) |
可以计算输入元素的总和 |
summarizingInt(ToIntFunction<? super T> mapper) |
可以计算输入元素的总和,平均值,数量,最值 |
summarizingLong(ToLongFunction<? super T> mapper) |
可以计算输入元素的总和,平均值,数量,最值 |
summarizingDouble(ToDoubleFunction<? super T> mapper) |
可以计算输入元素的总和,平均值,数量,最值 |
@Test
public void testSummary() {
List<Integer> lists = new ArrayList<>();
lists.add(1);
lists.add(2);
lists.add(3);
Integer sum = lists.stream().collect(Collectors.summingInt((item) -> item));
System.out.println(sum);
IntSummaryStatistics summary = lists.stream().collect(Collectors.summarizingInt((item) -> item));
System.out.println(summary.getSum());
System.out.println(summary.getAverage());
System.out.println(summary.getCount());
System.out.println(summary.getMax());
System.out.println(summary.getMin());
}
5、分组——groupingBy,groupingByConcurrent
方法 |
描述 |
groupingBy(Function<? super T, ? extends K> classifier) |
classifier提供结果Map(HashMap)的键 |
groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream) |
downstream提供结果Map和值 |
groupingBy(Function<? super T, ? extends K> classifier, Supplier<M> mapFactory, Collector<? super T, A, D> downstream) |
mapFactory指定结果Map的类型 |
groupingByConcurrent(Function<? super T, ? extends K> classifier) |
classifier提供结果Map(HashMap)的键,将元素整理成ConcurrentMap |
groupingByConcurrent(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream) |
downstream提供结果Map和值,将元素整理成ConcurrentMap |
groupingByConcurrent(Function<? super T, ? extends K> classifier, Supplier<M> mapFactory,Collector<? super T, A, D> downstream) |
mapFactory指定结果Map的类型,将元素整理成ConcurrentMap |
@Data
@Builder
static class Student{
private Long id;
private String name;
private Long classId;
private Integer age;
}
@Test
public void testGroup() {
List<Student> list = new ArrayList<>();
Student zhangSan = Student.builder().id(1L).name("张三").classId(1L).age(20).build();
Student liSi = Student.builder().id(2L).name("李四").classId(1L).age(21).build();
Student wangWu = Student.builder().id(3L).name("王五").classId(2L).age(21).build();
Student zhaoLiu = Student.builder().id(4L).name("赵六").classId(1L).age(21).build();
list.add(liSi);
list.add(zhangSan);
list.add(wangWu);
list.add(zhaoLiu);
//根据classId分组
Map<Long, List<Student>> map1 = list.stream().collect(Collectors.groupingBy(Student::getClassId));
System.out.println("map1:\n" + map1);
//统计各个classId的人数
Map<Long, Long> map2 = list.stream().collect(Collectors.groupingBy(Student::getClassId,
Collectors.counting()));
System.out.println("map2:\n" + map2);
//统计各个classId的人数
Map<Long, Long> map3 = list.stream().collect(Collectors.groupingBy(Student::getClassId,
HashMap::new,
Collectors.counting()));
System.out.println("map3:\n" + map3);
}
6、分区——partitioningBy
方法 |
描述 |
partitioningBy(Predicate<? super T> predicate) |
该操作将输入元素分为两类(即键是true和false的Map),predicate提供分区依据 |
partitioningBy(Predicate<? super T> predicate,Collector<? super T, A, D> downstream) |
该操作将输入元素分为两类(即键是true和false的Map),downstream提供结果Map的值 |
@Test
public void testPartitioning() {
List<Student> list = new ArrayList<>();
Student zhangSan = Student.builder().id(1L).name("张三").classId(1L).age(20).build();
Student liSi = Student.builder().id(2L).name("李四").classId(1L).age(21).build();
Student wangWu = Student.builder().id(3L).name("王五").classId(2L).age(21).build();
Student zhaoLiu = Student.builder().id(4L).name("赵六").classId(1L).age(21).build();
list.add(liSi);
list.add(zhangSan);
list.add(wangWu);
list.add(zhaoLiu);
Map<Boolean, List<Student>> map = list.stream().collect(Collectors.partitioningBy((item -> item.getAge() > 20)));
System.out.println("map:\n" + map);
Map<Boolean, Long> map1 = list.stream().collect(Collectors.partitioningBy((item -> item.getAge() > 20),
Collectors.counting()));
System.out.println("map1:\n" + map1);//{false=1, true=3}
}
7、Collector之后再操作——collectingAndThen
方法 |
描述 |
collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher) |
downstream(Collector类型)和finisher(Function类型),在调用downstream之后,将调用结果值作为finisher的传入值,再调用finisher。 |
@Test
public void testCollectingAndThen() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
String result = list.stream().collect(Collectors.collectingAndThen(Collectors.counting(),
(ret) -> "统计结果为=" + ret));
System.out.println(result);
}
8、拼接——joining
方法 |
描述 |
joining() |
将输入元素(字符串类型)拼接成字符串,拼接输入元素 |
joining(CharSequence delimiter) |
将输入元素(字符串类型)拼接成字符串,将delimiter作为分隔符 |
joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix) |
将输入元素(字符串类型)拼接成字符串,将prefix作为前缀,suffix作为后缀 |
@Test
public void testCollectingAndThen() {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
String result = list.stream().collect(Collectors.joining());
System.out.println(result);//abc
String result2 = list.stream().collect(Collectors.joining("-"));
System.out.println(result2);//a-b-c
String result3 = list.stream().collect(Collectors.joining(",", "[", "]"));
System.out.println(result3);//[a,b,c]
}
9、mapping
方法 |
描述 |
mapping(Function<? super T, ? extends U> mapper,Collector<? super U, A, R> downstream) |
mapper(Function类型)和downstream(Collector类型),在调用mapper之后,将调用结果的返回值作为downstream的输入元素,再调用downstream |
@Test
public void testMapping() {
List<Student> list = new ArrayList<>();
Student zhangSan = Student.builder().id(1L).name("张三").classId(1L).age(20).build();
Student liSi = Student.builder().id(2L).name("李四").classId(1L).age(21).build();
Student wangWu = Student.builder().id(3L).name("王五").classId(2L).age(21).build();
Student zhaoLiu = Student.builder().id(4L).name("赵六").classId(1L).age(21).build();
list.add(liSi);
list.add(zhangSan);
list.add(wangWu);
list.add(zhaoLiu);
String result = list.stream().collect(Collectors.mapping(Student::getName, Collectors.joining(",", "[", "]")));
System.out.println(result);//[李四,张三,王五,赵六]
}
10、缩减——reducing
方法 |
描述 |
reducing(BinaryOperator<T> op) |
对输入元素执行缩减操作,对输入的元素应用op操作 |
reducing(T identity, BinaryOperator<T> op) |
对输入元素执行缩减操作,提供初始值identity |
reducing(U identity, Function<? super T, ? extends U> mapper, BinaryOperator<U> op) |
对输入元素执行缩减操作,在对元素进行op操作之前,先进行mapper操作 |
@Test
public void testReducing() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
//求和,返回Optional
Optional<Integer> result = list.stream().collect(Collectors.reducing((a, b) -> a + b));
if (result.isPresent()){
System.out.println(result.get());//6
}
//求和,返回Integer
Integer result2 = list.stream().collect(Collectors.reducing(0, (a, b) -> a + b));
System.out.println(result2);//6
//每个元素先平方,再求和
Integer result3 = list.stream().collect(Collectors.reducing(0, item -> item * item, (a, b) -> a + b));
System.out.println(result3);//14
}
11、集合转化——toCollection、toList与toSet
方法 |
描述 |
toCollection(Supplier<C> collectionFactory) |
将输入元素整理成集合,collectionFactory可以指定结果集合的类型,将输入元素整理成集合 |
toList() |
将输入元素整理成集合,将输入元素整理成ArrayList |
toSet() |
将输入元素整理成集合,将输入元素整理成HashSet |
@Test
public void testToCollection() {
List<Student> list = new ArrayList<>();
Student zhangSan = Student.builder().id(1L).name("张三").classId(1L).age(20).build();
Student liSi = Student.builder().id(2L).name("李四").classId(1L).age(21).build();
Student wangWu = Student.builder().id(3L).name("王五").classId(2L).age(21).build();
Student zhaoLiu = Student.builder().id(4L).name("赵六").classId(1L).age(21).build();
list.add(liSi);
list.add(zhangSan);
list.add(wangWu);
list.add(zhaoLiu);
List<Student> toList = list.stream().filter(item -> item.getClassId().equals(1L)).collect(Collectors.toList());
Set<Student> toSet = list.stream().filter(item -> item.getClassId().equals(1L)).collect(Collectors.toSet());
ArrayList<Student> toCollection = list.stream().filter(item -> item.getClassId().equals(1L)).collect(Collectors.toCollection(ArrayList::new));
}
12、Map转化——toMap与toConcurrentMap
方法 |
描述 |
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper) |
将输入元素整理成Map,keyMapper和valueMapper分别提供结果Map的键和值 |
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction) |
将输入元素整理成Map,mergeFunction对键相同的值进行累积 |
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier) |
将输入元素整理成Map,mapSupplier可以指定结果的Map类型 |
@Test
public void testToMap() {
List<Student> list = new ArrayList<>();
Student zhangSan = Student.builder().id(1L).name("张三").classId(1L).age(20).build();
Student liSi = Student.builder().id(2L).name("李四").classId(1L).age(21).build();
Student wangWu = Student.builder().id(3L).name("王五").classId(2L).age(21).build();
Student zhaoLiu = Student.builder().id(4L).name("赵六").classId(1L).age(21).build();
list.add(liSi);
list.add(zhangSan);
list.add(wangWu);
list.add(zhaoLiu);
//转为map,存在相同的key的话会抛异常
Map<Long, String> map = list.stream().collect(Collectors.toMap(item -> item.getId(),
item -> item.getName()));
System.out.println(map);//{1=张三, 2=李四, 3=王五, 4=赵六}
//转化为map,若key相等,取后一个
Student zhaoLiu2 = Student.builder().id(4L).name("赵六2").classId(1L).age(21).build();
list.add(zhaoLiu2);
Map<Long, String> map1 = list.stream().collect(Collectors.toMap(item -> item.getId(),
item -> item.getName(),
(a, b) -> b));
System.out.println(map1);//{1=张三, 2=李四, 3=王五, 4=赵六2}
//指定返回的map类型为TreeMap
TreeMap<Long, String> map3 = list.stream().collect(Collectors.toMap(item -> item.getId(),
item -> item.getName(),
(a, b) -> b,
TreeMap::new));
System.out.println(map3);//{1=张三, 2=李四, 3=王五, 4=赵六2}
}
参考文章:https://www.jianshu.com/p/ac2bcf2f9d48
参考文章:https://blog.csdn.net/xiliunian/article/details/88773718
参考文章:https://blog.csdn.net/weixin_44187730/article/details/93737517