- 一、Stream流简介
- 1.1 什么是Stream流?
- 1.2 为什么使用Stream流?
- 1.3 Stream流的特性
- 二、创建Stream流
- 2.1 通过 Collection 扩展接口创建流
- 2.2 由数组创建流
- 2.3 由值创建流
- 2.4 由函数创建流
- 三、Stream流的中间操作
- 3.1 筛选与切片
- 3.2 映射
- 3.3 排序
- 四、Stream流的终止操作
- 4.1 查找与匹配
- 4.2 归约
- 4.3 收集
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
———摘自菜鸟教程
1.2 为什么使用Stream流?流是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
集合讲的是数据,流讲的是计算!
Stream流可以对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。Stream API 借助于同样新出现的Lambda表达式,极大的提高编程效率和程序可读性。
1.3 Stream流的特性- Stream 自己不会存储元素。
- Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
- Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
一个数据源(如:集合、数组),获取一个流。
2.1 通过 Collection 扩展接口创建流Collection 接口被扩展,提供了两个获取流的方法。
default Stream
default Stream
List2.2 由数组创建流list = Arrays.asList("1", "2", "3", "zs", "abc"); Stream stream1 = list.stream(); Stream stream2 = list.parallelStream();
Arrays 的静态方法 stream() 可以获取数组流。
static
IntStream intStream = Arrays.stream(new int[]{1, 2, 3});
LongStream longStream = Arrays.stream(new long[]{123L, 46L});
DoubleStream doubleStream = Arrays.stream(new double[]{12.3, 34.56});
2.3 由值创建流
可以使用静态方法 Stream.of(), 通过显示值创建一个流。它可以接收任意数量的参数。
public static
Stream2.4 由函数创建流streamValue = Stream.of("a", "b", "c");
可以使用静态方法 Stream.iterate() 和Stream.generate(), 创建无限流。
迭代 public static
生成 public static
//迭代(需要传入一个种子,也就是起始值,然后传入一个一元操作) Stream三、Stream流的中间操作integerStream = Stream.iterate(2, (x) -> x * 2); //生成(无限产生对象) Stream doubleStream = Stream.generate(() -> Math.random());
一个中间操作链,对数据源的数据进行处理。
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。
3.1 筛选与切片| 方法 | 描述 |
|---|---|
| filter(Predicate p) | 接收 Lambda , 从流中排除某些元素。 |
| distinct() | 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素 |
| limit(long maxSize) | 截断流,使其元素不超过给定数量。 |
| skip(long n) | 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补 |
// 1、匿名内部类的方式 Stream3.2 映射filterStream1 = userEntities.stream(); filterStream1.filter(new Predicate () { @Override public boolean test(UserEntity userEntity) { return userEntity.getAge() >= 35; } }).filter(new Predicate () { @Override public boolean test(UserEntity userEntity) { return userEntity.getName().equals("zhangsan"); } }).forEach(new Consumer () { @Override public void accept(UserEntity userEntity) { System.out.println("匿名内部类的方式进行过滤:" + userEntity.toString()); } }); // 2、lambda的方式 相关条件可以使用&&符合拼接,也可以再次使用filter Stream filterStream2 = userEntities.stream(); filterStream2.filter(userEntity -> userEntity.getAge() >= 35 && userEntity.getName().equals("zhangsan")) .forEach(userEntity -> System.out.println("lambda的方式进行过滤:" + userEntity.toString())); // limit就是从头开始获取 // skip就是表示跳过 Stream limitStream = userEntities.stream(); limitStream.skip(2).limit(1).forEach(userEntity -> System.out.println("使用skip和limit:" + userEntity));
| 方法 | 描述 |
|---|---|
| map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。 |
| mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。 |
| mapToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。 |
| mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。 |
| flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 |
List3.3 排序userList = Arrays.asList(new UserEntity("a",1),new UserEntity("ab",3),new UserEntity("c",11),new SUserEntityu("f",12)); Stream stream = userList .stream(); // 去除list中所有的年龄 stream.map(UserEntity::getAge).forEach(System.out::println); // 把所有年龄再返回一个集合 List collect = stream.map(UserEntity::getAge).collect(Collectors.toList()); stream.flatMap(userEntity-> test1.filterCharacter(userEntity.getName())).forEach(System.out::println);
| 方法 | 描述 |
|---|---|
| sorted() | 产生一个新流,其中按自然顺序排序 |
| sorted(Comparator comp) | 产生一个新流,其中按比较器顺序排序 |
// 1、匿名内部类的方式 Stream四、Stream流的终止操作sortedStream1 = userEntities.stream(); sortedStream1.sorted(new Comparator () { @Override public int compare(UserEntity o1, UserEntity o2) { // 升序 return o1.getAge() - o2.getAge(); } }).forEach(new Consumer () { @Override public void accept(UserEntity userEntity) { System.out.println("使用匿名内部类的方式排序:" + userEntity.toString()); } }); // 2、lambda的方式 Stream sortedStream2 = userEntities.stream(); sortedStream2.sorted((o1, o2) -> o1.getAge() - o2.getAge()) .forEach(userEntity -> System.out.println("使用lambda的方式排序:" + userEntity.toString()));
一个终止操作,执行中间操作链,并产生结果。
4.1 查找与匹配| 方法 | 描述 |
|---|---|
| allMatch(Predicate p) | 检查是否匹配所有元素 |
| anyMatch(Predicate p) | 检查是否至少匹配一个元素 |
| noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
| findFirst() | 返回第一个元素 |
| findAny() | 返回当前流中的任意元素 |
| count() | 返回流中元素总数 |
| max(Comparator c) | 返回流中最大值 |
| min(Comparator c) | 返回流中最小值 |
| forEach(Consumer c) | 内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了) |
// 1、匿名内部类的方式 Stream4.2 归约noneMatch1 = userEntities.stream(); boolean result = noneMatch1.noneMatch(new Predicate () { @Override public boolean test(UserEntity userEntity) { return userEntity.getAge() > 32; } }); System.out.println("noneMatch使用匿名内部类的方式:" + result); // 2、lambda的方式 Stream noneMatch2 = userEntities.stream(); boolean result2 = noneMatch2.noneMatch((user) -> user.getAge() > 35); System.out.println("noneMatch使用lambda的方式:" + result2); // 1、匿名内部类的方式 Stream allMatch1 = userEntities.stream(); boolean result3 = allMatch1.allMatch(new Predicate () { @Override public boolean test(UserEntity userEntity) { return userEntity.getAge() < 54; } }); System.out.println("allMatch使用匿名内部类的方式:" + result3); // 2、lambda的方式 Stream allMatch2 = userEntities.stream(); boolean result4 = allMatch2.allMatch((user) -> user.getAge() <54); System.out.println("allMatch使用lambda的方式:" + result4); // 1、匿名内部类的方式 Stream anyMatch1 = userEntities.stream(); boolean result5 = anyMatch1.anyMatch(new Predicate () { @Override public boolean test(UserEntity userEntity) { return userEntity.getAge() > 20; } }); System.out.println("anyMatch使用匿名内部类的方式:" + result5); // 2、lambda的方式 Stream anyMatch2 = userEntities.stream(); boolean result6 = anyMatch2.anyMatch((user) -> user.getAge() > 20); System.out.println("anyMatch使用lambda的方式:" + result6);
| 方法 | 描述 |
|---|---|
| reduce(T iden, BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。 返回 T |
| reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回 Optional< T > |
// 1、使用匿名内部类的方式 Stream4.3 收集integerStream1 = Stream.of(10, 30, 80, 60, 10, 70); Optional reduce = integerStream1.reduce(new BinaryOperator () { @Override public Integer apply(Integer integer, Integer integer2) { return integer + integer2; } }); System.out.println(reduce.get()); // 2、使用lambda的方式 Stream integerStream2 = Stream.of(10, 30, 80, 60, 10, 70); Optional reduce2 = integerStream2.reduce((a1, a2) -> a1 + a2); System.out.println(reduce2.get()); // 1、使用匿名内部类的方式 Stream objStream1 = userEntities.stream(); Optional reduce3 = objStream1.reduce(new BinaryOperator () { @Override public UserEntity apply(UserEntity userEntity, UserEntity userEntity2) { userEntity.setAge(userEntity.getAge() + userEntity2.getAge()); return userEntity; } }); System.out.println(reduce3.get().getAge()); // 2、使用lambda的方式 Stream objStream2 = userEntities.stream(); Optional reduce4 = objStream2.reduce((user1, user2) -> { user1.setAge(user1.getAge() + user2.getAge()); return user1; }); System.out.println(reduce4.get().getAge());
| 方法 | 描述 |
|---|---|
| collect(Collector c) | 将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法 |
Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下:
| 方法 | 返回类型 | 描述 |
|---|---|---|
| toList | List< T > | 把流中元素收集到List |
| toSet | Set< T > | 把流中元素收集到Set |
| toCollection | Collection< T > | 把流中元素收集到创建的集合 |
| counting | Long | 计算流中元素的个数 |
| summingInt | Integer | 对流中元素的整数属性求和 |
| averagingInt | Double | 计算流中元素Integer属性的平均值 |
| summarizingInt | IntSummaryStatistics | 收集流中Integer属性的统计值。 如:平均值 |
| joining | String | 连接流中每个字符串 |
| maxBy | Optional< T > | 根据比较器选择最大值 |
| minBy | Optional< T > | 根据比较器选择最小值 |
| reducing | 归约产生的类型 | 从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而归约成单个值 |
| collectingAndThen | 转换函数返回的类型 | 包裹另一个收集器,对其结果转换函数 |
| groupingBy | Map | 根据某属性值对流分组,属性为K,结果为V |
| partitioningBy | Map | 根据true或false进行分区 |
Streamstream1 = userEntities.stream(); Set collectSet = stream1.collect(Collectors.toSet()); System.out.println(collectSet); Stream stream2 = userEntities.stream(); Map collectMap = stream2.collect(Collectors.toMap( // String对应map中的key new Function () { @Override public String apply(UserEntity userEntity) { return userEntity.getName(); } }, // UserEntity对应map中的value new Function () { @Override public UserEntity apply(UserEntity userEntity) { return userEntity; } })); // 遍历将键值输出 collectMap.forEach(new BiConsumer () { @Override public void accept(String s, UserEntity userEntity) { System.out.println("s:" + s + ",:" + userEntity.toString()); } });



