一、Stream流简介
1.1 什么是Stream流?
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 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
二、创建Stream流
一个数据源(如:集合、数组),获取一个流。
2.1 通过 Collection 扩展接口创建流
Collection 接口被扩展,提供了两个获取流的方法。
default Stream<E> stream()
: 返回一个顺序流default Stream<E> parallelStream()
: 返回一个并行流
/** * Collection 扩展接口 * 通过 Collection 的 Stream()方法或 parallelStream()方法创建 Stream */ System.out.println("======Collection======"); List<String> list = Arrays.asList("1", "2", "3", "zs", "abc"); Stream<String> stream1 = list.stream(); Stream<String> stream2 = list.parallelStream();
小贴士:
并行流就是把一个内容分成多个数据块,并用不同的线程分别处理没歌数据块的流。
Java 8中将并行进行了优化,我们可以很容易的对数据进行并行操作。Stream API 可以声明性地通过 parallel() 与 sequential() 在并行流与顺序流之间进行切换。
2.2 由数组创建流
Arrays 的静态方法 stream() 可以获取数组流。
static <T> Stream<T> stream(T[] array): 返回一个流
/** * 由数组创建流 * 通过 Arrays中的静态方法 stream() 获取数组流 */ System.out.println("======Arrays======"); 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}); Integer[] integerNums = new Integer[10]; Long[] longNums = new Long[10]; Double[] doubleNums = new Double[10]; Stream<Integer> integerStream2 = Arrays.stream(integerNums); Stream<Long> longStream2 = Arrays.stream(longNums);
2.3 由值创建流
可以使用静态方法 Stream.of(), 通过显示值创建一个流。它可以接收任意数量的参数。
public static<T> Stream<T> of(T... values)
:返回一个流
/** * 由值创建流 * 通过 Stream()类中的 of()静态方法获取流 */ System.out.println("======of()======"); Stream<String> streamValue = Stream.of("a", "b", "c");
2.4 由函数创建流
可以使用静态方法 Stream.iterate()
和 Stream.generate()
创建无限流。
迭代:public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
生成:public static<T> Stream<T> generate(Supplier<T> s)
System.out.println("======function()======"); //迭代(需要传入一个种子,也就是起始值,然后传入一个一元操作) Stream<Integer> integerStream3 = Stream.iterate(0, x -> x + 2).limit(10); integerStream3.forEach(System.out::println); //生成(无限产生对象) Stream<Double> doubleStream3 = Stream.generate(() -> Math.random()); doubleStream3.forEach(System.out::println);
三、Stream流的中间操作
一个中间操作链,对数据源的数据进行处理。
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。
/** * 中间操作 */ List<UserEntity> userList = new ArrayList<>(); userList.add(new UserEntity("zhangsan", 20)); userList.add(new UserEntity("lisi", 28)); userList.add(new UserEntity("wangwu", 35)); userList.add(new UserEntity("xiaoming", 16)); userList.add(new UserEntity("Amay", 36)); userList.add(new UserEntity("Jack", 45));
3.1 筛选与切片
方法 | 描述 |
---|---|
filter(Predicate p) | 接收 Lambda , 从流中排除某些元素。 |
distinct() | 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素 |
limit(long maxSize) | 截断流,使其元素不超过给定数量。 |
skip(long n) | 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补 |
/** * 筛选与切片 * filter:接受 Lambda,从流中排出某些元素; * limit:截断流,使其元素不超过给定数量; * skip(n):跳过元素,返回一个扔掉了前 n 个元素的流。如果流中元素不足 n个,就返回一个空流。(与 limit(n) 互补) * distinct:筛选,通过流所生成元素的 hashCode()和equals()去除重复元素。 */ // 1、filter System.out.println("======filter======"); // 外部迭代(Java 8之前做的都是外部迭代) System.out.println("======外部迭代======"); Iterator<UserEntity> iterator = userList.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } // 内部迭代:迭代操作在 Stream API 内部完成(对外部迭代进行的优化) System.out.println("======内部迭代======"); System.out.println("测试中间操作...过滤所有年龄小于25的user对象"); Stream<UserEntity> stream = userList.stream() // 所有的中间操作不会做任何处理 .filter(userEntity -> { return userEntity.getAge() <= 25; }); // 只有当做终止操作时,所有的中间操作会一次性的全部执行,这称为"惰性求值" stream.forEach(System.out::println); // 2、limit System.out.println("======limit======"); System.out.println("测试中间操作...过滤后限定数量不超过3"); userList.stream().filter(userEntity -> userEntity.getAge() >= 30) .limit(3).forEach(System.out::println); // 3、skip System.out.println("======skip======"); System.out.println("测试中间操作...过滤后跳过前2个元素"); userList.stream().filter(userEntity -> userEntity.getAge() >= 15) .skip(2).forEach(System.out::println); // 4、distinct System.out.println("======distinct======"); System.out.println("测试中间操作...通过distinct进行筛选"); userList.stream().distinct().forEach(System.out::println);
3.2 映射
方法 | 描述 |
---|---|
map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。 |
mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。 |
mapToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。 |
mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。 |
flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 |
/** * 映射 */ List<UserEntity> userList = Arrays.asList(new UserEntity("a",1),new UserEntity("ab",3),new UserEntity("c",11),new SUserEntityu("f",12)); Stream<UserEntity> stream = userList .stream(); // 去除list中所有的年龄 stream.map(UserEntity::getAge).forEach(System.out::println); // 把所有年龄再返回一个集合 List<Integer> collect = stream.map(UserEntity::getAge).collect(Collectors.toList()); stream.flatMap(userEntity-> test1.filterCharacter(userEntity.getName())).forEach(System.out::println);
3.3 排序
方法 | 描述 |
---|---|
sorted() | 产生一个新流,其中按自然顺序排序 |
sorted(Comparator comp) | 产生一个新流,其中按比较器顺序排序 |
/** * stream排序sorted */ // 1、匿名内部类的方式 Stream<UserEntity> sortedStream1 = userEntities.stream(); sortedStream1.sorted(new Comparator<UserEntity>() { @Override public int compare(UserEntity o1, UserEntity o2) { // 升序 return o1.getAge() - o2.getAge(); } }).forEach(new Consumer<UserEntity>() { @Override public void accept(UserEntity userEntity) { System.out.println("使用匿名内部类的方式排序:" + userEntity.toString()); } }); // 2、lambda的方式 Stream<UserEntity> sortedStream2 = userEntities.stream(); sortedStream2.sorted((o1, o2) -> o1.getAge() - o2.getAge()) .forEach(userEntity -> System.out.println("使用lambda的方式排序:" + userEntity.toString()));
四、Stream流的终止操作
一个终止操作,执行中间操作链,并产生结果。
/** * 终止操作 */ List<UserEntity> userList = new ArrayList<>(); userList.add(new UserEntity("zhangsan", 20)); userList.add(new UserEntity("lisi", 28)); userList.add(new UserEntity("wangwu", 35)); userList.add(new UserEntity("xiaoming", 16)); userList.add(new UserEntity("Amay", 36)); userList.add(new UserEntity("Jack", 45));
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 使用内部迭代——它帮你把迭代做了) |
/** * streamMatch匹配--noneMatch * noneMatch表示判断条件里的元素,所有的都不是,就返回true */ System.out.println("======noneMatch======"); // 1、匿名内部类的方式 Stream<UserEntity> noneMatch1 = userList.stream(); boolean result = noneMatch1.noneMatch(new Predicate<UserEntity>() { @Override public boolean test(UserEntity userEntity) { return userEntity.getAge() > 32; } }); System.out.println("noneMatch使用匿名内部类的方式:" + result); // 2、lambda的方式 Stream<UserEntity> noneMatch2 = userList.stream(); boolean result2 = noneMatch2.noneMatch((user) -> user.getAge() > 35); System.out.println("noneMatch使用lambda的方式:" + result2); /** * streamMatch匹配--allMatch * allMatch表示判断条件里的元素,所有都是就返回true */ System.out.println("======allMatch======"); // 1、匿名内部类的方式 Stream<UserEntity> allMatch1 = userList.stream(); boolean result3 = allMatch1.allMatch(new Predicate<UserEntity>() { @Override public boolean test(UserEntity userEntity) { return userEntity.getAge() < 54; } }); System.out.println("allMatch使用匿名内部类的方式:" + result3); // 2、lambda的方式 Stream<UserEntity> allMatch2 = userList.stream(); boolean result4 = allMatch2.allMatch((user) -> user.getAge() <54); System.out.println("allMatch使用lambda的方式:" + result4); /** * streamMatch匹配--anyMatch */ System.out.println("======anyMatch======"); // 1、匿名内部类的方式 Stream<UserEntity> anyMatch1 = userList.stream(); boolean result5 = anyMatch1.anyMatch(new Predicate<UserEntity>() { @Override public boolean test(UserEntity userEntity) { return userEntity.getAge() > 20; } }); System.out.println("anyMatch使用匿名内部类的方式:" + result5); // 2、lambda的方式 Stream<UserEntity> anyMatch2 = userList.stream(); boolean result6 = anyMatch2.anyMatch((user) -> user.getAge() > 20); System.out.println("anyMatch使用lambda的方式:" + result6); /** * findFirst */ System.out.println("======findFirst======"); Optional<UserEntity> findFirst = userList.stream().sorted(((o1, o2) -> Double.compare(o1.getAge(), o2.getAge()))).findFirst(); System.out.println("findFirst:" + findFirst.get()); /** * findAny */ System.out.println("======findAny======"); Optional<UserEntity> findAny = userList.stream().filter(userEntity -> userEntity.getName().equalsIgnoreCase("zhangsan")).findAny(); System.out.println("findAny:" + findAny.get()); /** * max */ System.out.println("======max======"); Optional<Integer> max = userList.stream().map(UserEntity::getAge).max(Double::compare); System.out.println("max:" + max); /** * min */ System.out.println("======min======"); Optional<Integer> min = userList.stream().map(UserEntity::getAge).min(Double::compare); System.out.println("min:" + min);
注意:流进行了终止操作后不能再次使用!
4.2 归约
方法 | 描述 |
---|---|
reduce(T iden, BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。 返回 T |
reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回 Optional<T> |
/** * stream将reduce求和--基本数据类型 */ System.out.println("======reduce——基本数据类型======"); // 1、使用匿名内部类的方式 Stream<Integer> integerStream1 = Stream.of(10, 30, 80, 60, 10, 70); Optional<Integer> reduce = integerStream1.reduce(new BinaryOperator<Integer>() { @Override public Integer apply(Integer integer, Integer integer2) { return integer + integer2; } }); System.out.println(reduce.get()); // 2、使用lambda的方式 Stream<Integer> integerStream2 = Stream.of(10, 30, 80, 60, 10, 70); Optional<Integer> reduce2 = integerStream2.reduce((a1, a2) -> a1 + a2); System.out.println(reduce2.get()); /** * stream将reduce求和--对象 */ System.out.println("======reduce——对象======"); // 1、使用匿名内部类的方式 // 1、使用匿名内部类的方式 Stream<UserEntity> objStream1 = userEntities.stream(); Optional<UserEntity> reduce3 = objStream1.reduce(new BinaryOperator<UserEntity>() { @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<UserEntity> objStream2 = userEntities.stream(); Optional<UserEntity> reduce4 = objStream2.reduce((user1, user2) -> { user1.setAge(user1.getAge() + user2.getAge()); return user1; }); System.out.println(reduce4.get().getAge());
4.3 收集
方法 | 描述 |
---|---|
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, List< T >> | 根据某属性值对流分组,属性为K,结果为V |
partitioningBy | Map<Boolean, List< T >> | 根据true或false进行分区 |
/** * collect——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法。 */ // toList():把流中元素收集到 List System.out.println("======toList()======"); List<String> collectList = userList.stream().map(UserEntity::getName).collect(Collectors.toList()); collectList.forEach(System.out::println); // toSet():把流中元素收集到 Set System.out.println("======toSet()======"); Set<String> collectSet = userList.stream().map(UserEntity::getName).collect(Collectors.toSet()); collectSet.forEach(System.out::println); // toCollection():把流中元素收集到创建的集合 System.out.println("======toCllection()======"); HashSet<String> collectHashSet = userList.stream().map(UserEntity::getName).collect(Collectors.toCollection(HashSet::new)); collectHashSet.forEach(System.out::println); // counting():计算流中元素的个数 System.out.println("======counting()======"); Long collectLong = userList.stream().collect(Collectors.counting()); System.out.println("流中元素的个数:" + collectLong); // summingInt():对流中元素的整数属性求和 System.out.println("======summingInt()======"); Integer summingInt = userList.stream().collect(Collectors.summingInt(UserEntity::getAge)); System.out.println("对流中的整数属性求和:" + summingInt); // summarizingInt():收集流中Integer属性的统计值。 如:平均值 System.out.println("======summarizingInt()======"); IntSummaryStatistics intSummaryStatistics = userList.stream().collect(Collectors.summarizingInt(UserEntity::getAge)); System.out.println("平均值:" + intSummaryStatistics.getAverage()); System.out.println("最大值:" + intSummaryStatistics.getMax()); // joining():连接流中每个字符串("以什么符号分割", "以什么符号开头", "以什么符号结尾") System.out.println("======joining()======"); String joiningStr = userList.stream().map(UserEntity::getName).collect(Collectors.joining(",", "---", "---")); System.out.println(joiningStr); // maxBy():根据比较器选择最大值 System.out.println("======maxBy()======"); Optional<Integer> collectMaxBy = userList.stream().map(UserEntity::getAge).collect(Collectors.maxBy(Integer::compare)); System.out.println(collectMaxBy.get()); // minBy():根据比较器选择最小值 System.out.println("======minBy()======"); Optional<UserEntity> collectMinBy = userList.stream().collect(Collectors.minBy(((o1, o2) -> Integer.compare(o1.getAge(), o2.getAge())))); System.out.println(collectMinBy.get()); // reducing():从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而归约成单个值 System.out.println("======reducing()======"); Optional<Integer> collectReducing = userList.stream().map(UserEntity::getAge).collect(Collectors.reducing(Integer::sum)); System.out.println(collectReducing); // groupingBy():根据某属性值对流分组,属性为K,结果为V System.out.println("======groupingBy()======"); Map<Integer, List<UserEntity>> listMap = userList.stream().collect(Collectors.groupingBy(UserEntity::getAge)); System.out.println("根据年龄对流分组:" + listMap); // 多级分组 Map<Integer, Map<String, List<UserEntity>>> groupMap = userList.stream().collect(Collectors.groupingBy(UserEntity::getAge, Collectors.groupingBy(u -> { if (u.getAge() >= 60) return "老年"; else if (u.getAge() >= 35) return "中年"; else return "成年"; }))); System.out.println(groupMap); // partitioningBy():根据true或false进行分区 System.out.println("======partitioningBy()======"); Map<Boolean, List<UserEntity>> partitioningMap = userList.stream().collect(Collectors.partitioningBy(u -> u.getAge() >= 500)); System.out.println(partitioningMap);
摘自:https://blog.csdn.net/qq_50994235/article/details/121457158