java8 stream使用速查手册

1. 概述

1.1 流的概述

流在管道中传输,且可以在管道的节点上进行处理,比如排序,聚合,过滤等操作

1.2 操作详情

  • 元素书记便是原始集合,如List、Set、Map等
  • 生成流,可以是串行流stream()或者并行流parallelStream()
  • 中间操作,可以是排序、聚合、过滤、转换等
  • 终端操作,很多流操作本会就会返回一个流,所以多个操作可以直接连接起来,最后统一进行收集
  • 概念stream接口源码

1.3 简单实例

List<String> list = new ArrayList<>();
list.add("test1");
list.add("test2");
list.add("test3");

list.stream().map(str -> str.toUpperCase()).collect(Collectors.toList());

2. map、filter和flatMap函数

2.1 map函数

  • 将流中的每个元素T映射为R(类似于类型转换)
  • 场景转换,如javaweb开发中集合里面的DO对象转换为DTO对象
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");

List<Integer> integerList = list.stream().map(Integer::parseInt).collect(Collectors.toList());
System.out.println(integerList);

2.2 filter函数

  • 用于通过设置的条件过滤出元素
// 过滤出字符长度大于5的
List<String> list = new ArrayList<>();
list.add("test1");
list.add("test12");
list.add("test123");

List<String> resultList = list.stream().filter(str -> str != null && str.length() > 5).collect(Collectors.toList());
System.out.println(resultList);

2.3 flatMap函数

flatMap方法接受一个lambda表达式函数,函数的返回值必须也是一个stream类型,flatMap方法最终会把所有返回的stream合并

List<String> list1 = new ArrayList<>(2);
list1.add("test1");
list1.add("test2");

List<String> list2 = new ArrayList<>(2);
list2.add("test4");
list2.add("test5");

List<List<String>> lists = new ArrayList<>(2);
lists.add(list1);
lists.add(list2);

lists.stream()
     // 将其中所有的list合并成一个流输出
    .flatMap(list -> list.stream())
    .forEach(str -> System.out.println(str));

2.4 注意事项

map与filter函数都是惰性求值操作,在调用collect、count等及早求值操作前,不会执行函数中的内部代码

List<String> list = new ArrayList<>(3);
list.add("test1");
list.add("test2");
list.add("tes");

// 并不会打印11
list.stream().filter(str -> {
    System.out.println("11");
    return str.startsWith("test");
});

3.sorted与limit函数

3.1 sorted函数

实现一

  • sorted函数对流进行自然排序,其中的元素必须实现Comparable接口

先构造一个实现了Comparable接口的类

public class Student implements Comparable<Student>{
    private String name = null;
    private int age = 0;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(Student student) {
        return this.age - student.age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试代码

Student stu1 = new Student("name1", 12);
Student stu2 = new Student("name2", 13);

List<Student> list = new ArrayList<>(2);
list.add(stu2);
list.add(stu1);
System.out.println(list);

List<Student> resultList = list.stream().sorted().collect(Collectors.toList());
System.out.println(resultList);

实现二

sorted(Comparator<? super T> comparator) ⽤用来⾃自定义升降序

Student stu1 = new Student("name1", 12);
Student stu2 = new Student("name2", 13);
List<Student> list = new ArrayList<>(2);
list.add(stu2);
list.add(stu1);

// 法一:
// List<Student> resultList = list.stream().sorted(Comparator.comparing(stu -> stu.getAge())).collect(Collectors.toList());

// 法二
// Comparator.reverseOrder() 表示反序
List<Student> resultList = list.stream().sorted(Comparator.comparing(stu -> stu.getAge(), Comparator.reverseOrder())).collect(Collectors.toList());

System.out.println(resultList);

3.2 limit函数

截断流使其最多只包含指定数量的元素

List<String> list = new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
list.add("444");

List<String> resultList = list.stream().limit(3).collect(Collectors.toList());
System.out.println(resultList);

4. allMatch与anyMatch

4.1allMatch函数

检查是否匹配所有元素,只有全部符合才返回true

List<String> list = new ArrayList<>();
list.add("1");
list.add("22");
list.add("333");
list.add("4444");

boolean result = list.stream().allMatch(str -> str.length() < 3);
// false
System.out.println(result);

4.2 anyMatch

检查是否匹配所有元素,只有全部符合才返回trueanyMatch函数

List<String> list = new ArrayList<>();
list.add("1");
list.add("22");
list.add("333");
list.add("4444");

boolean result = list.stream().anyMatch(str -> str.length() < 3);
// true
System.out.println(result);

5. max和min函数

最⼤值和最小值

Student stu1 = new Student("name1", 12);
Student stu2 = new Student("name2", 13);
Student stu3 = new Student("name3", 14);
List<Student> list = new ArrayList<>(3);

list.add(stu2);
list.add(stu1);
list.add(stu3);

Optional<Student> max = list.stream().max(Comparator.comparing(stu -> stu.getAge()));
Optional<Student> min = list.stream().min((stud1, stud2) -> Integer.compare(stud1.getAge(), stud2.getAge()));
System.out.println(max);
System.out.println(min);

6. 并行流paralleStream

6.1 为什么会有并行流

集合做重复的操作,如果使用串行执行会相当耗时,因此一般会采用多线程来加快,java8的paralleStream用fork/join框架提供了并发执行的能力

6.2 底层原理

  • 线程池(ForkJoinPool)维护一个线程队列
  • 可以分割任务,将父任务拆分成子任务,完全贴合分治思想

6.3 两个区别

List<String> list = new ArrayList<String>();
list.add("1");
list.add("22");
list.add("333");
list.add("4444");

// 乱序输出
list.parallelStream().forEach(str -> System.out.println(str));

System.out.println("------------------------------------");

// 顺序输出
list.stream().forEach(str -> System.out.println(str));

6.4 问题

  • paralleStream并行是否一定比Stream串行快
    不是,数据量少的情况,可能串行更快,ForkJoin会消耗性能。
    下例我们尝试检测性能差距
List<String> list = new ArrayList<String>(1000000);
for(int i = 0; i < 1000000; i++) {
    list.add(String.valueOf(i));
}

/*
long streamStartTime = System.currentTimeMillis();
list.stream().forEach(str -> System.out.println(str));
long streamEndTime = System.currentTimeMillis();

// 耗时3589毫秒
System.out.println(streamEndTime - streamStartTime);
 */

long paralleStreamStartTime = System.currentTimeMillis();
list.stream().forEach(str -> System.out.println(str));
long paralleStreamEndTime = System.currentTimeMillis();

// 耗时3512
System.out.println(paralleStreamEndTime - paralleStreamStartTime);

可以看出性能差距并不明显,并行流在实际中是否有用还需观察

  • 是否可都用并行
    不行,部分情况会有线程安全问题,paralleStream里面使用的外部变量,比如集合一定要使用线程安全集合,不然就会引发多线程安全问题

7. reduce操作

7.1 简介

  • 聚合操作,中文意思是减少
  • 根据一定的规则将Stream中的元素进行计算后返回一个唯一的值

7.2 常用方法

方法一

Optional<T> reduce(BinaryOperator<T> accumulator);

实例:

将集合中所有元素求和输出

List<Integer> list = new ArrayList<>(4);
list.add(1);
list.add(2);
list.add(3);
list.add(4);

System.out.println(list.stream().reduce((item1, item2) -> item1 + item2).get());

常用方法二

T reduce(T identity, BinaryOperator<T> accumulator);
  • identity用户提供一个循环计算的初始值
  • accumulator计算的累加器

实例:
100作为初始值,然后和第一个元素相加,结果在和第二个元素相加,知道全部相加完成

List<Integer> list = new ArrayList<>(4);
list.add(1);
list.add(2);
list.add(3);
list.add(4);

System.out.println(list.stream().reduce(100 ,(sum, item2) -> sum + item2));

7.3 综合实例

求数组中元素的最大值

List<Integer> list = new ArrayList<>(4);
list.add(1);
list.add(2);
list.add(3);
list.add(4);

System.out.println(list.stream().reduce((item1, item2) -> item1 > item2 ? item1 : item2).get());

8. forEach操作

8.1 简介

jdk8里面新增的接口

8.2 实例操作

List<Integer> list = new ArrayList<>(4);
list.add(1);
list.add(2);
list.add(3);
list.add(4);

list.stream().forEach(item -> System.out.println(item));

8.3 注意点

  • 不能修改包含外部变量的值
  • 不能用break或者return或者continue等关键字结束或跳过循环

9 collector收集器

9.1 collect()方法的作用

  • 一个终端操作,对于流中的数据进行归集操作,collect方法接受的参数是一个Collector
  • 有两个重载方法,在Stream接口里面

9.2 Collector的作用

就是收集器,也是一个接口,它的工具类Collectors提供了很多工厂方法

9.2 Collectors的作用

工具类,提供了很多常见的收集器实现

  • Collectors.toList()
  • Collectors.toMap()
  • Collectors.toSet()
  • Collectors.toCollection():用自定义的实现Collection的数据结构收集
    • Collectors.toCollection(LinkedList::new)
    • Collectors.toCollection(CopyOnWriteArrayList::new)
    • Collectors.toCollection(TreeSet::new)

10. 收集器joining函数

拼接函数Collectors.joining

10.1 三种重载方法

Collectors.joining()
Collectors.joing("param")
Collectors.joing("param1","param2","param3")

10.2 实例:

List<String> list = new ArrayList<>(4);
list.add("1");
list.add("2");
list.add("3");
list.add("4");

String result1 = list.stream().collect(Collectors.joining());
// 输出1234
System.out.println(result1);

String result2 = list.stream().collect(Collectors.joining(","));
// 输出1,2,3,4
System.out.println(result2);

String result3 = list.stream().collect(Collectors.joining(",", "[", "]"));
// 输出[1,2,3,4]
System.out.println(result3);

11.收集器partitioningBy分组

11.1 简介

讲解收集器partitioningBy分组
Collectors.partitioningBy分组,key是boolean类型

11.2 实例

对list进行分组,字符串长度大于3的为一组,其他为另外一组

List<String> list = new ArrayList<>(4);
list.add("1");
list.add("22");
list.add("333");
list.add("4444");

Map<Boolean, List<String>> result = list.stream().collect(Collectors.partitioningBy(str -> str.length() > 3));
// 输出{false=[1, 22, 333], true=[4444]}
System.out.println(result);

12.收集器groupingBy分组

分组统计:

  • 聚合函数进行统计查询,分组后统计个数
  • Collectors.counting()统计元素个数
  • 底层也是HashMap实现,所以分组的依据是equals和hashCode

实例代码:

Student stu1 = new Student("name1", 12);
Student stu2 = new Student("name2", 13);
Student stu3 = new Student("name3", 14);
List<Student> list = new ArrayList<>(3);

list.add(stu2);
list.add(stu1);
list.add(stu1);
list.add(stu3);

Map<String, List<Student>> resultMap1 = list.stream().collect(Collectors.groupingBy(Student::getName));
Map<String, Long> resultMap2 = list.stream().collect(Collectors.groupingBy(Student::getName, Collectors.counting()));

// 输出{name3=[Student{name='name3', age=14}], name2=[Student{name='name2', age=13}], name1=[Student{name='name1', age=12}, Student{name='name1', age=12}]}
System.out.println(resultMap1);
// 输出{name3=1, name2=1, name1=2}
System.out.println(resultMap2);

13. summarizing集合统计

作用:可以一个方法把统计相关的基本上都完成
分类:

  • summarizingInt
  • summarizingLong
  • summarizingDouble

实例:统计学生的各个年龄信息

Student stu1 = new Student("name1", 12);
Student stu2 = new Student("name2", 13);
Student stu3 = new Student("name3", 14);
List<Student> list = new ArrayList<>(3);

list.add(stu2);
list.add(stu1);
list.add(stu1);
list.add(stu3);

DoubleSummaryStatistics summaryStatistics = list.stream().collect(Collectors.summarizingDouble(Student::getAge));
System.out.println("平均值" + summaryStatistics.getAverage());
System.out.println("最大值" + summaryStatistics.getMax());
System.out.println("最小值" + summaryStatistics.getMin());
System.out.println("人数" + summaryStatistics.getCount());
System.out.println("总和" + summaryStatistics.getSum());

输出结果

平均值12.75
最大值14.0
最小值12.0
人数4
总和51.0

14. count

count() 方法计算给定Stream里包含多少个对象

List<String> list = new ArrayList<>(3);
list.add("test1");
list.add("test2");
list.add("tes");

long count = list.stream().filter(str -> str.startsWith("test")).count();
// 输出2
System.out.println(count);

15. Stream.of

Stream.of操作可以生成流

Stream<Integer> integerStream = Stream.of(11, 33, 44);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值