写点什么

java 中的 Stream 实践

用户头像
林一
关注
发布于: 2021 年 05 月 21 日

概述

​ java 中的流是在 Java Se8 中引人的,用来以“做什么而非怎么做”的方式处理集合。它可以让我们编写的代码更优雅,下面总结了几种常用的方式来使用流。

如何生成流

在 Java 8 中, 集合接口有两个方法来生成流:


  • stream() − 为集合创建串行流。

  • parallelStream() − 为集合创建并行流。


List<String> names= Lists.newArrayList("ll", "jj", "mm");System.out.print("stream输出结果:");names.stream().forEach(x -> System.out.print(x + "、"));System.out.println();System.out.print("parallelStream输出结果:");names.parallelStream().forEach(x -> System.out.print(x + "、"));
复制代码


输出结果如下:


可以看到 stream()的结果输出跟 list 的顺序一致但是 parallelStream()结果确实乱序的,因为 parallelStream()是并行流


其它方式创建流:


  • 如果你有一个数组,可以用如下方式创建流


String[] nums = new String[]{"1", "2", "3"};Stream.of(nums);//使用Arrays.stream(nums,from,to)可以从数组中位于from(包括)和to(不包括)的元素中创建一个流Arrays.stream(nums, 1, 3);
复制代码


  • 如果你需要生成 10 个随机数可以用如下的方式创建流


Stream.generate(Math::random).limit(10);
复制代码


其中 Stream.generate(Supplier<T> s)是一个可以生成无限流的方式,它的值是反复调用函数 s 来生成的,搭配上 .limit(10)可以来指定循环次数。

常用的 filter、map 和 flatMap 方法

  • Stream<T> filter(Predicate<? super T> predicate); 生成一个流,它包含当前流中所有满足断言条件的元素。


String[] names = new String[]{"张三", "李四", "王五"};System.out.println(Stream.of(names).filter("张三"::equals).collect(Collectors.toList()));
复制代码


输出结果如下:



  • <R> Stream<R> map(Function<? super T, ? extends R> mapper); 产生一个流,它包含将 mapper 应用于当前流中所有元素所产生的结果。


String[] names = new String[]{"张三", "李四", "王五"};List<Person> collect = Stream.of(names).map(x -> {    Person person = new Person();    person.setName(x);    return person;}).collect(Collectors.toList());System.out.println(collect);
复制代码


输出结果如下:



  • <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper); 产生一个流,它是通过将 mapper 应用于当前流中所有元素所产生的结果(每个结果都是一个流)连接到一起而获得的,也就是将流打平。


它在实践中的常用的一个场景就是:假设你一个 order 有 userIdCreate 和 userIdUpdate,你需要收集所有 id 批量查询他们的姓名此时你就可以使用类似如下的代码:


Set<String> userIdSet = Stream.generate(() -> {    Order order = new Order();    order.setUserIdCreate(UUID.randomUUID().toString());    order.setUserIdUpdate(UUID.randomUUID().toString());    return order;}).limit(2).flatMap(e -> Stream.of(e.getUserIdCreate(), e.getUserIdUpdate())).collect(Collectors.toSet());System.out.println(userIdSet);
复制代码


输出结果如下:



抽取子流和连接流

  • Stream<T> limit(long maxSize); 产生一个流,其中包含了当前流中最初的 maxsize 个元素。

  • Stream<T> skip(long n); 产生一个流,它的元素是当前流中除了前 n 个元素之外的所有元素。

  • static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) 产生一个流,它的元素是 a 的元素后面跟着 b 的元素。


调用 stream.1imit(n)会返回一个新的流,它在 n 个元素之后结束(如果原来的流更短,那么就会在流结束时结束)。这个方法对于裁剪无限流的尺寸会显得特别有用。例如上文提到的生成一个随机数:


Stream.generate(Math::random).limit(10);
复制代码


然而调用 stream.skip(n) 它会丢弃前 n 个元素。这里个人感觉最好用的场景就是用来做内存分页,例如如下代码:


List<Person> personList = Lists.newArrayList(new Person("张三", 1)        , new Person("李四", 2), new Person("王五", 3));
Pageable pageable = PageRequest.of(1, 1);//获取分页的数据List<Person> pageResult = personList.stream() .skip(pageable.getOffset()) .limit(pageable.getPageSize()).collect(Collectors.toList());System.out.println(pageResult);
复制代码


运行结果如下:


这里要说明一下,page 中第一页用 0 来表示,所以 PageRequest.of(1, 1);其实是取第二页。


Stream.concat(a, b)可以进行流合并,代码如下:


System.out.println(Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 5, 6)).collect(Collectors.toList()));
复制代码


运行结果如下:


其它常用方法

  • Stream<T> distinct(); 去重

  • Stream<T> sorted(Comparator<? super T> comparator); 排序

  • Optional<T> max(Comparator<? super T> comparator); 取最大值

  • Optional<T> min(Comparator<? super T> comparator); 取最小值

  • boolean anyMatch(Predicate<? super T> predicate); 部分匹配

  • boolean allMatch(Predicate<? super T> predicate); 全部匹配

  • boolean noneMatch(Predicate<? super T> predicate); 全部不匹配

  • groupingBy(Function<? super T, ? extends K> classifier) 分组

  • collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher) 收集再处理


//去重 distinct()        Lists.newArrayList(1, 1).stream().distinct().forEach(x -> System.out.println("distinct():" + x));        //排序 sorted(Comparator<? super T> comparator)        List<Integer> sortResult = Lists.newArrayList(1, 2, 3)                .stream()                .sorted(Comparator.comparing(Integer::intValue).reversed())                .collect(Collectors.toList());        System.out.println("sorted():" + sortResult);        //最大 max(Comparator<? super T> comparator) 最小 min(Comparator<? super T> comparator)        System.out.println("max():" + Lists.newArrayList(1, 2, 3).stream().max(Comparator.comparing(Integer::intValue)).get());        System.out.println("min():" + Lists.newArrayList(1, 2, 3).stream().min(Comparator.comparing(Integer::intValue)).get());        //部分匹配:anyMatch(),全部匹配allMatch(),全部不匹配noneMatch()        System.out.println("anyMatch():" + Lists.newArrayList(1, 2, 30).stream().anyMatch(x -> x < 10));        System.out.println("allMatch():" + Lists.newArrayList(1, 2, 30).stream().allMatch(x -> x < 10));        System.out.println("noneMatch():" + Lists.newArrayList(1, 2, 30).stream().noneMatch(x -> x > 30));        //分组        Map<String, List<Person>> nameGroupBy = Lists.newArrayList(new Person("张三", 10), new Person("李四", 10), new Person("张三", 10))                .stream()                .collect(Collectors.groupingBy(Person::getName));        System.out.println("groupingBy():" + nameGroupBy);        //收集完的结果再处理        Set<String> collectingAndThen = Lists.newArrayList(new Person("张三", 10), new Person("李四", 10), new Person("张三", 10))                .stream()                .collect(Collectors.collectingAndThen(Collectors.groupingBy(Person::getName), Map::keySet));        System.out.println("collectingAndThen():" + collectingAndThen);
复制代码


结果如下:


用户头像

林一

关注

没有幽默的笔风👉 2020.02.13 加入

还未添加个人简介

评论

发布
暂无评论
java中的Stream实践