概述
java 中的流是在 Java Se8 中引人的,用来以“做什么而非怎么做”的方式处理集合。它可以让我们编写的代码更优雅,下面总结了几种常用的方式来使用流。
如何生成流
在 Java 8 中, 集合接口有两个方法来生成流:
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);
复制代码
Stream.generate(Math::random).limit(10);
复制代码
其中 Stream.generate(Supplier<T> s)是一个可以生成无限流的方式,它的值是反复调用函数 s 来生成的,搭配上 .limit(10)可以来指定循环次数。
常用的 filter、map 和 flatMap 方法
String[] names = new String[]{"张三", "李四", "王五"};
System.out.println(Stream.of(names).filter("张三"::equals).collect(Collectors.toList()));
复制代码
输出结果如下:
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);
复制代码
输出结果如下:
它在实践中的常用的一个场景就是:假设你一个 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);
复制代码
结果如下:
评论