1、前言
阅读本文你需要 具有Lambda的一些技术知识。
2、什么是Stream?
Stream它并不是一个容器,它只是对容器的功能进行了增强,添加了很多便利的操作,例如查找、过滤、分组、排序等一系列的操作。并且有串行、并行两种执行模式,并行模式充分的利用了多核处理器的优势,使用fork/join框架进行了任务拆分,同时提高了执行速度。简而言之,Stream就是提供了一种高效且易于使用的处理数据的方式。
- 特点:
- Stream自己不会存储元素。
- Stream的操作不会改变源对象。相反,他们会返回一个持有结果的新Stream。
- Stream 操作是延迟执行的。它会等到需要结果的时候才执行。也就是执行终端操作的时候。
一个Stream的操作就如上图,在一个管道内,分为三个步骤,第一步是创建Stream,从集合、数组中获取一个流,第二步是中间操作链,对数据进行处理。第三步是终端操作,用来执行中间操作链,返回结果。
2、1 先来看一下Stream接口
红框的意义
红色圈起来的是中间操作,因为我可以很明显的看出来,调用方法之后返回的还是一个Stream流
3、Stream的中间操作
3、1 去重
Stream`<T>` distinct();
去重,通过流所生成元素的 hashCode() 和 equals() 去除重复元素。
3、2 过滤
Stream<T> filter(Predicate<? super T> predicate);
按照我们的设置的规则过滤到不需要的值
在过滤的时候可以结合lambda表达式 Stream.of(xxx).filter(o -> "xx".equals(o.getXxx()));
其中 o代码当前流中的每一个对象
default Stream<T> dropWhile(Predicate<? super T> predicate);
default Stream<T> takeWhile(Predicate<? super T> predicate);
当条件满足的时候删除元素,
当条件满足的时候留下元素,
3、3 元素操作
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
对集合内每一项元素操作并返回、同理mapToInt、mapToLong、mapToDouble是转换成一个数字的流。
如果使用方法引用Stream.of(xxx).map(xxx::getXxx).forEach(System.out::println);那么是将Stream内部的每一个元素转化成get方法得到的属性,也可以自定义方法,对流中的元素操作。但是一定要有返回值,最后的到的流就是所有的返回值组成的数据。
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
flatMap是将一个流中的集合转为操作流的一个方法
Stream.of( 对象 ).flapMap(o -> o.getXxx().stream()).forEach(System.out::println);
实现下列的效果需要这样使用
Stream.of(employees1, employees2).flatMap(e -> Arrays.stream(e)).forEach(System.out::println);
Stream<T> peek(Consumer<? super T> action);
peek的操作类似于map,🥚是
peek()
一般用于不想改变流中元素本身的类型或者只想操作元素的内部状态时;而map()
则用于改变流中元素本身类型,即从元素中派生出另一种类型的操作。
3、4 排序
Stream<T> sorted();
Stream<T> sorted(Comparator<? super T> comparator);
可以使用默认的排序
或者我们可以自行传入一个比较器,待(wo)补(bu)充(hui);
3、5 限制个数
Stream<T> limit(long maxSize);
截断流,使其元素不超过给定数量。如果元素的个数小于maxSize,那就获取所有元素。
3、6 跳过
Stream<T> skip(long n);
跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与
limit
互补。
4、 终端操作
4、1 迭代
void forEach(Consumer<? super T> action);
void forEachOrdered(Consumer<? super T> action);
是一个无返回值的消费型接口
users.stream().forEach(user -> System.out.println(user.getName())); users.stream().forEach(System.out::println);
使用并行流进行操作时,
forEachOrdered()
会严格按照顺序进行输出,而forEach()
不会。
4、2 转数组
<A> A[] toArray(IntFunction<A[]> generator);
Object[] toArray();
无参数的没有什么好说的,直接转成一个object的数组。重点看有参数的
将流转化为特定的数组 将流转换成一个指定的数组
4、3 待补充
T reduce(T identity, BinaryOperator<T> accumulator);
Optional<T> reduce(BinaryOperator<T> accumulator);
<U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);
我也不会 希望会的人把文章和链接送上。
4、4 最大、最小、总数
Optional<T> min(Comparator<? super T> comparator);
Optional<T> max(Comparator<? super T> comparator);
long count();
求最大、最小值,参数是一个比较器,比较器没有什么可说的简单来说就是((o1,o2)->o1.getAge-o2.getAge)
求流中数据的总数。
4、5 匹配是否存在
boolean anyMatch(Predicate<? super T> predicate);
boolean noneMatch(Predicate<? super T> predicate);
boolean noneMatch(Predicate<? super T> predicate);
match
是匹配操作,它总共有三类方法:anyMatch
、allMatch
和noneMatch
。
anyMatch
用于检查所有元素中至少有一个是匹配的。它的方法如下:
allMatch
用于检查所有元素是否都匹配。方法如下:
noneMatch
用于检查所有元素都没有匹配的。方法如下:
4、6 查找
Optional<T> findFirst();
Optional<T> findAny();
两个方法都是查找第一个,但是findAny在并行流中有相对将较好的效率。
4、7 收集器
<R, A> R collect(Collector<? super T, A, R> collector);
收集、将流转换为其他形式,比如转换成List、Set、Map。collect方法是用Collector作为参数,Collector接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例。例举一些常用的:
List<User> users = Lists.newArrayList();
users.add(new User(15, "A", ImmutableList.of("1元", "5元")));
users.add(new User(25, "B", ImmutableList.of("10元", "50元")));
users.add(new User(21, "C", ImmutableList.of("100元")));
//收集名称到List
List<String> nameList = users.stream().map(User::getName).collect(Collectors.toList());
//收集名称到List
Set<String> nameSet = users.stream().map(User::getName).collect(Collectors.toSet());
//收集到map,名字作为key,user对象作为value
Map<String, User> userMap = users.stream().collect(Collectors.toMap(User::getName, Function.identity(), (k1, k2) -> k2));
// 对数据过滤之后转换为原来的list。
user.stream().filter(o-> "1".equals(o.getName()))
.collect(Collectors.toCollection(ArrayList::new));