目录
第一篇:JDK8新特性一:引入介绍
第二篇:JDK8新特性二:Lambda表达式引入介绍
第三篇:JDK8新特性二:Lambda表达式规范和语法
第四篇:JDK8新特性二:方法引入详述
第五篇:JDK8新特性二:foreach、排序、线程调用简单示例
第六篇:JDK8新特性三:Stream流+常见方法演示
第七篇:JDK8新特性四:Optional类的学习
Stream流
1 什么是Stream流
- java.util.stream.Stream
- Stream是JDK1.8中处理集合的关键抽象概念,Lambda和Stream是JDK1.8新增的函数式编程最有亮点的特性,它可以指定我们需要对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用StreamAPI对集合数据进行操作,类似于使用SQL执行数据库查询。Stream使用一种类似用SQL语句从数据库查询数据的直观方式来提供一种对Java集合运算和表达的抽象。Stream API可以极大提高Java编程的生产力,让程序员写出高效率、干净、简洁的代码。
- 这种风格将要处理的元素集合看做一种流,流在管道中传输,并且可以在管道的节点上进行处理,比如筛选、排序、聚合等。
- 元素流在管道中经过中间操作的处理,最后由最终操作得到前面处理之后的结果。
- 示例图
- Stream操作的步骤
- 创建Stream:一个数据源(如集合、数组),获取一个流
- 中间操作:一个操作链,对数据源的数据进行处理
- 终止操作:一个终止操作,执行中间操作链并产生结果
2 Stream创建方式
-
两种Stream流创建方式
- stream:是串行流,采用单线程执行
- parallelStream:是并行流,采用多线程执行
-
获取流的方式
-
根据Collection获取流
- 从Collection接口源码中可以看到,其中添加了default方法stream用来获取流对象,因此该接口的所有实现类都可以通过这种方式获取流
// 1. Collection获取流 List<String> list = new ArrayList<>(); Stream<String> stream1 = list.stream(); Set<String> set = new HashSet<>(); Stream<String> stream2 = set.stream(); Vector<String> vector = new Vector<>(); Stream<String> stream3 = vector.stream();
-
根据Map获取流
- Map接口并不是Collection接口的子接口,因此没法直接通过stream()方式获取流,此外因为Map是K-V形式的结构数据,不符合流元素的单一特征,因此还要划分Key、Value、entry等方面
// 2. 根据Map获取流 Map<String, String> map = new HashMap<>(); Stream<String> keyStream = map.keySet().stream(); Stream<String> valueStream = map.values().stream(); Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();
-
根据数组获取流
- 数组对象不存在默认方法,在Stream接口中的静态方法of可以用来操作数据获取流
// 3. 通过数组获取流 String[] strArr = { "111","222","333"}; Stream<String> strStream = Stream.of(strArr);
- Stream.of的形参是可变参数,可以接收数组为参数,也可以给定一个元素序列,返回一个流对象
- 对于数组的操作,还可以使用Arrays.stream(T arr)来操作
-
-
流的常见方法,后面案例会用一部分来演示
-
分类
- 延迟方法:返回值仍然是Stream接口自身类型的方法,因此支持链式调用。(除了终结方法之外的方法都是延迟方法)
- 终结方法:返回值类型不再是Stream接口自身类型的方法,因此不再支持类似StringBuilder那样的链式调用。终结方法包括count和forEach等方法。
-
举例
forEach:遍历处理 filter:过滤 map:处理映射 reduce:元素反复结合,生成一个值 count:统计个数 limit:截取前几个 skip:忽略前几个 concat:流合并为一个流 sorted:排序 allMatch:检查是否匹配所有元素 anyMatch:检查是否至少匹配一个元素 noneMatch:检查是否一个都没有匹配 findFirst:返回第一个元素 findAny:返回任意一个元素 max:返回最大值 min:返回最小值 collect:将流转换其他形式
-
3 Stream将List转换为Set
-
使用到的方法
- stream.collect(Collectors.toSet())
-
测试实体类
@Data @AllArgsConstructor public class TestEntity { private String name; private Integer age; }
-
测试
List<TestEntity> list = new ArrayList<>(); TestEntity tom2 = new TestEntity("Tom2", 2); list.add(new TestEntity("Tom1",1)); list.add(tom2); list.add(new TestEntity("Tom3",3)); list.add(tom2); list.add(new TestEntity("Tom5",5)); // 创建Stream流 Stream<TestEntity> stream = list.stream(); // 1. 将List集合转换为Set,乱序|不允许重复|返回Set为HashSet Set<TestEntity> set = stream.collect(Collectors.toSet()); System.out.println(set);
-
说明
- 集合中的泛型实体类必须要重写hashCode方法,因为stream.collect(Collectors.toSet())方法返回的Set是HashSet类型,它对速度进行了优化,存入HashSet的元素必须定义hashCode()方法。同时在良好编程风格来看,同样需要重写equals方法
- 测试代码中,添加的两个tom2指向同一个对象,因此转换为Set对象之后,只会保留一个
- 可以进入toSet()方法源码,这里指明了方法返回值是什么具体的Set类型
4 Stream将List转换为Map
-
测试实体类
@Data @AllArgsConstructor @NoArgsConstructor public class TestEntity { private String name; private Integer age; }
-
测试代码
List<TestEntity> list = new ArrayList<>(); list.add(new TestEntity("Tom1",1)); list.add(new TestEntity("Tom2",2)); list.add(new TestEntity("Tom3",3)); list.add(new TestEntity("Tom4",4)); list.add(new TestEntity("Tom5",5)); // 创建Stream流 Stream<TestEntity> stream = list.stream(); // 将List集合转换为Map // Map<String, TestEntity> collect = stream.collect(Collectors.toMap(new Function<TestEntity, String>() { // @Override // public String apply(TestEntity testEntity) { // return testEntity.getName(); // } // }, new Function<TestEntity, TestEntity>() { // @Override // public TestEntity apply(TestEntity testEntity) { // return testEntity; // } // })); // Lambda优化 Map<String, TestEntity> collect = stream.