Java8新特性Stream的完全使⽤指南
什么是Stream
Stream是Java 1.8版本开始提供的⼀个接⼝,主要提供对数据集合使⽤流的⽅式进⾏操作,流中的元素不可变且只会被消费⼀次,所有⽅法都设计成⽀持链式调⽤。使⽤Stream API可以极⼤⽣产⼒,写出⾼效率、⼲净、简洁的代码。
如何获得Stream实例
Stream提供了静态构建⽅法,可以基于不同的参数创建返回Stream实例
使⽤Collection的⼦类实例调⽤stream()或者parallelStream()⽅法也可以得到Stream实例,两个⽅法的区别在于后续执⾏Stream其他⽅法的时候是单线程还是多线程
Stream<String> stringStream = Stream.of("1", "2", "3");
//⽆限长的偶数流
Stream<Integer> evenNumStream = Stream.iterate(0, n -> n + 2);
List<String> strList = new ArrayList<>();
strList.add("1");
strList.add("2");
strList.add("3");
Stream<String> strStream = strList.stream();
Stream<String> strParallelStream = strList.parallelStream();
filter
filter⽅法⽤于根据指定的条件做过滤,返回符合条件的流
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3);
//获得只包含正数的流,positiveNumStream -> (1,2,3)
Stream<Integer> positiveNumStream = numStream.filter(num -> num > 0);
map
map⽅法⽤于将流中的每个元素执⾏指定的转换逻辑,返回其他类型元素的流
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3);
//转换成字符串流
Stream<String> strStream = numStream.map(String::valueOf);
mapToInt mapToLong mapToDouble
这三个⽅法是对map⽅法的封装,返回的是官⽅为各个类型单独定义的Stream,该Stream还提供了适合各⾃类型的其他操作⽅法
Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3");
IntStream intStream = stringStream.mapToInt(Integer::parseInt);
LongStream longStream = stringStream.mapToLong(Long::parseLong);
DoubleStream doubleStream = stringStream.mapToDouble(Double::parseDouble);
flatMap
flatMap⽅法⽤于将流中的每个元素转换成其他类型元素的流,⽐如,当前有⼀个订单(Order)列表,每个订单⼜包含多个商品(itemList),如果要得到所有订单的所有商品汇总,就可以使⽤该⽅法,如下:
Stream<Item> allItemStream = orderList.stream().flatMap(order -> order.itemList.stream());
flatMapToInt flatMapToLong flatMapToDouble
这三个⽅法是对flatMap⽅法的封装,返回的是官⽅为各个类型单独定义的Stream,使⽤⽅法同上
distinct
distinct⽅法⽤于对流中的元素去重,判断元素是否重复使⽤的是equals⽅法
Stream<Integer> numStream = Stream.of(-2, -1, 0, 0, 1, 2, 2, 3);
//不重复的数字流,uniqueNumStream -> (-2, -1, 0, 1, 2, 3)
Stream<Integer> uniqueNumStream = numStream.distinct();
sorted
sorted有⼀个⽆参和⼀个有参的⽅法,⽤于对流中的元素进⾏排序。⽆参⽅法要求流中的元素必须实现Comparable接⼝,不然会报java.lang.ClassCastException异常
Stream<Integer> unorderedStream = Stream.of(5, 6, 32, 7, 27, 4);
//按从⼩到⼤排序完成的流,orderedStream -> (4, 5, 6, 7, 27, 32)
Stream<Integer> orderedStream = unorderedStream.sorted();
有参⽅法sorted(Comparator<? super T> comparator)不需要元素实现Comparable接⼝,通过指定的元素⽐较器对流内的元素进⾏排序
Stream<String> unorderedStream = Stream.of("1234", "123", "12", "12345", "123456", "1");
//按字符串长度从⼩到⼤排序完成的流,orderedStream -> ("1", "12", "123", "1234", "12345", "123456")
Stream<String> orderedStream = unorderedStream.sorted(ComparatorparingInt(String::length));
peek
peek⽅法可以不调整元素顺序和数量的情况下消费每⼀个元素,然后产⽣新的流,按⽂档上的说明,主
要是⽤于对流执⾏的中间过程做debug的时候使⽤,因为Stream使⽤的时候⼀般都是链式调⽤的,所以可能会执⾏多次流操作,如果想看每个元素在多次流操作中间的流转情况,就可以使⽤这个⽅法实现
Stream.of("one", "two", "three", "four")
.filter(e -> e.length() > 3)
.peek(e -> System.out.println("Filtered value: " + e))
.map(String::toUpperCase)
.peek(e -> System.out.println("Mapped value: " + e))
.List());
输出:
Filtered value: three
Mapped value: THREE
Filtered value: four
Mapped value: FOUR
limit(long maxSize)
limit⽅法会对流进⾏顺序截取,从第1个元素开始,保留最多maxSize个元素
Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3");
equals()方法//截取前3个元素,subStringStream -> ("-2", "-1", "0")
Stream<String> subStringStream = stringStream.limit(3);
skip(long n)
skip⽅法⽤于跳过前n个元素,如果流中的元素数量不⾜n,则返回⼀个空的流
Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3");
//跳过前3个元素,subStringStream -> ("1", "2", "3")
Stream<String> subStringStream = stringStream.skip(3);
forEach
forEach⽅法的作⽤跟普通的for循环类似,不过这个可以⽀持多线程遍历,但是不保证遍历的顺序
Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3");
//单线程遍历输出元素
stringStream.forEach(System.out::println);
//多线程遍历输出元素
stringStream.parallel().forEach(System.out::println);
forEachOrdered
forEachOrdered⽅法可以保证顺序遍历,⽐如这个流是从外部传进来的,然后在这之前调⽤过parallel⽅法开启了多线程执⾏,就可以使⽤这个⽅法保证单线程顺序遍历
Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3");
//顺序遍历输出元素
stringStream.forEachOrdered(System.out::println);
//多线程遍历输出元素,下⾯这⾏跟上⾯的执⾏结果是⼀样的
//stringStream.parallel().forEachOrdered(System.out::println);
toArray
toArray有⼀个⽆参和⼀个有参的⽅法,⽆参⽅法⽤于把流中的元素转换成Object数组
Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3");
Object[] objArray = Array();
有参⽅法toArray(IntFunction<A[]> generator)⽀持把流中的元素转换成指定类型的元素数组Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3");
String[] strArray = Array(String[]::new);
reduce
reduce有三个重载⽅法,作⽤是对流内元素做累进操作
第⼀个reduce(BinaryOperator<T> accumulator)
accumulator 为累进操作的具体计算
单线程等下如下代码
boolean foundAny = false;
T result = null;
for (T element : this stream) {
if (!foundAny) {
foundAny = true;
result = element;
}
else
result = accumulator.apply(result, element);
}
return foundAny ? Optional.of(result) : pty();
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3);
//查最⼩值
Optional<Integer> min = duce(BinaryOperator.minBy(Integer::compareTo));
//输出 -2
System.out.());
//过滤出⼤于5的元素流
numStream = Stream.of(-2, -1, 0, 1, 2, 3).filter(num -> num > 5);
//查最⼩值
min = duce(BinaryOperator.minBy(Integer::compareTo));
//输出 pty
System.out.println(min);
第⼆个reduce(T identity, BinaryOperator<T> accumulator)
identity 为累进操作的初始值
accumulator 同上
单线程等价如下代码
T result = identity;
for (T element : this stream)
result = accumulator.apply(result, element)
return result;
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3);
//累加计算所有元素的和,sum=3
int sum = duce(0, Integer::sum);
第三个reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner) identity和accumulator同上
combiner⽤于多线程执⾏的情况下合并最终结果
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3);
int sum = numStream.parallel().reduce(0, (a, b) -> {
System.out.println("accumulator执⾏:" + a + " + " + b);
return a + b;
}, (a, b) -> {
System.out.println("combiner执⾏:" + a + " + " + b);
return a + b;
});
System.out.println("最终结果:"+sum);
输出:
accumulator执⾏:0 + -1
accumulator执⾏:0 + 1
accumulator执⾏:0 + 0
accumulator执⾏:0 + 2
accumulator执⾏:0 + -2
accumulator执⾏:0 + 3
combiner执⾏:2 + 3
combiner执⾏:-1 + 0
combiner执⾏:1 + 5
combiner执⾏:-2 + -1
combiner执⾏:-3 + 6
最终结果:3
collect
collect有两个重载⽅法,主要作⽤是把流中的元素作为集合转换成其他Collection的⼦类,其内部实现类似于前⾯的累进操作第⼀个collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner)
supplier 需要返回开始执⾏时的默认结果
accumulator ⽤于累进计算⽤
combiner ⽤于多线程合并结果
单线程执⾏等价于如下代码
R result = ();
for (T element : this stream)
accumulator.accept(result, element);
return result;
第⼆个collect(Collector<? super T, A, R> collector)
collector其实是对上⾯的⽅法参数的⼀个封装,内部执⾏逻辑是⼀样的,只不过JDK提供了⼀些默认的Collector实现Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3);
List<Integer> numList = List());
Set<Integer> numSet = Set());
min
min⽅法⽤于计算流内元素的最⼩值
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3);
Optional<Integer> min = numStream.min(Integer::compareTo);
max
min⽅法⽤于计算流内元素的最⼤值
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3);
Optional<Integer> max = numStream.max(Integer::compareTo);
count
count⽅法⽤于统计流内元素的总个数
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3);
//count=6
long count = unt();
anyMatch
anyMatch⽅法⽤于匹配校验流内元素是否有符合指定条件的元素
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3);
//判断是否包含正数,hasPositiveNum=true
boolean hasPositiveNum = numStream.anyMatch(num -> num > 0);
allMatch
allMatch⽅法⽤于匹配校验流内元素是否所有元素都符合指定条件
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3);
//判断是否全部是正数,allNumPositive=false
boolean allNumPositive = numStream.allMatch(num -> num > 0);
noneMatch
noneMatch⽅法⽤于匹配校验流内元素是否都不符合指定条件
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3);
//判断是否没有⼩于0的元素,noNegativeNum=false
boolean noNegativeNum = Match(num -> num < 0);
findFirst
findFirst⽅法⽤于获取第⼀个元素,如果流是空的,则返回pty
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3);
//获取第⼀个元素,firstNum=-2
Optional<Integer> firstNum = numStream.findFirst();
findAny
findAny⽅法⽤于获取流中的任意⼀个元素,如果流是空的,则返回pty,因为可能会使⽤多线程,所以不保证每次返回的是同⼀个元素
Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3);
Optional<Integer> anyNum = numStream.findAny();
总结
到此这篇关于Java8新特性Stream的完全使⽤指南就介绍到这了,更多相关Java8 Stream使⽤指南内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论