Java8--stream()的使用
-
什么是Stream
Stream是Java 1.8版本开始提供的一个接口,主要提供对数据集合使用流的方式进行操作,流中的元素不可变且只会被消费一次,所有方法都设计成支持链式调用。使用Stream API可以极大生产力,写出高效率、干净、简洁的代码。 -
如何获得Stream实例
Stream提供了静态构建方法,可以基于不同的参数创建返回Stream实例
使用Collection的子类实例调用stream()或者parallelStream()方法也可以得到Stream实例,两个方法的区别在于后续执行Stream其他方法的时候是单线程还是多线程Stream
stringStream = Stream.of("1", "2", "3"); //无限长的偶数流 Stream evenNumStream = Stream.iterate(0, n -> n + 2); List strList = new ArrayList<>(); strList.add("1"); strList.add("2"); strList.add("3"); Stream strStream = strList.stream(); Stream strParallelStream = strList.parallelStream(); 3.filter
filter方法用于根据指定的条件做过滤,返回符合条件的流StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); //获得只包含正数的流,positiveNumStream -> (1,2,3) Stream positiveNumStream = numStream.filter(num -> num > 0); 4.map
map方法用于将流中的每个元素执行指定的转换逻辑,返回其他类型元素的流StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); //转换成字符串流 Stream strStream = numStream.map(String::valueOf); 5.
mapToInt mapToLong mapToDouble
这三个方法是对
map方法的封装,返回的是官方为各个类型单独定义的Stream,该Stream还提供了适合各自类型的其他操作方法StreamstringStream = 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); 6.
flatMap
flatMap方法用于将流中的每个元素转换成其他类型元素的流,比如,当前有一个订单(Order)列表,每个订单又包含多个商品(itemList),如果要得到所有订单的所有商品汇总,就可以使用该方法,如下:Stream
- allItemStream = orderList.stream().flatMap(order -> order.itemList.stream());
flatMapToInt flatMapToLong flatMapToDouble
这三个方法是对
flatMap方法的封装,返回的是官方为各个类型单独定义的Stream,使用方法同上7.distinct
distinct方法用于对流中的元素去重,判断元素是否重复使用的是equals方法StreamnumStream = Stream.of(-2, -1, 0, 0, 1, 2, 2, 3); //不重复的数字流,uniqueNumStream -> (-2, -1, 0, 1, 2, 3) Stream uniqueNumStream = numStream.distinct(); 8.
sorted
sorted有一个无参和一个有参的方法,用于对流中的元素进行排序。无参方法要求流中的元素必须实现Comparable接口,不然会报java.lang.ClassCastException异常StreamunorderedStream = Stream.of(5, 6, 32, 7, 27, 4); //按从小到大排序完成的流,orderedStream -> (4, 5, 6, 7, 27, 32) Stream orderedStream = unorderedStream.sorted(); 有参方法
sorted(Comparator<? super T> comparator)不需要元素实现Comparable接口,通过指定的元素比较器对流内的元素进行排序StreamunorderedStream = Stream.of("1234", "123", "12", "12345", "123456", "1"); //按字符串长度从小到大排序完成的流,orderedStream -> ("1", "12", "123", "1234", "12345", "123456") Stream orderedStream = unorderedStream.sorted(Comparator.comparingInt(String::length)) 9.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)) .collect(Collectors.toList()); 输出: Filtered value: three Mapped value: THREE Filtered value: four Mapped value: FOUR10.limit(long maxSize)
limit方法会对流进行顺序截取,从第1个元素开始,保留最多maxSize个元素StreamstringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); //截取前3个元素,subStringStream -> ("-2", "-1", "0") Stream subStringStream = stringStream.limit(3); 11.skip(long n)
skip方法用于跳过前n个元素,如果流中的元素数量不足n,则返回一个空的流StreamstringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); //跳过前3个元素,subStringStream -> ("1", "2", "3") Stream subStringStream = stringStream.skip(3); 12.forEach
forEach方法的作用跟普通的for循环类似,不过这个可以支持多线程遍历,但是不保证遍历的顺序StreamstringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); //单线程遍历输出元素 stringStream.forEach(System.out::println); //多线程遍历输出元素 stringStream.parallel().forEach(System.out::println); 13.toArray
toArray有一个无参和一个有参的方法,无参方法用于把流中的元素转换成Object数组StreamstringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); Object[] objArray = stringStream.toArray(); 有参方法
toArray(IntFunction generator)支持把流中的元素转换成指定类型的元素数组StreamstringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); String[] strArray = stringStream.toArray(String[]::new); 14.reduce
reduce有三个重载方法,作用是对流内元素做累进操作第一个
reduce(BinaryOperatoraccumulator) 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) : Optional.empty();StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); //查找最小值 Optional min = numStream.reduce(BinaryOperator.minBy(Integer::compareTo)); //输出 -2 System.out.println(min.get()); //过滤出大于5的元素流 numStream = Stream.of(-2, -1, 0, 1, 2, 3).filter(num -> num > 5); //查找最小值 min = numStream.reduce(BinaryOperator.minBy(Integer::compareTo)); //输出 Optional.empty System.out.println(min); 第二个
reduce(T identity, BinaryOperatoraccumulator) identity为累进操作的初始值accumulator同上单线程等价如下代码
T result = identity; for (T element : this stream) result = accumulator.apply(result, element) return result;StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); //累加计算所有元素的和,sum=3 int sum = numStream.reduce(0, Integer::sum); collect
collect有两个重载方法,主要作用是把流中的元素作为集合转换成其他Collection的子类,其内部实现类似于前面的累进操作第一个
collect(Suppliersupplier, BiConsumer accumulator, BiConsumer combiner) supplier需要返回开始执行时的默认结果accumulator用于累进计算用combiner用于多线程合并结果单线程执行等价于如下代码
R result = supplier.get(); for (T element : this stream) accumulator.accept(result, element); return result;第二个
collect(Collector<? super T, A, R> collector)collector其实是对上面的方法参数的一个封装,内部执行逻辑是一样的,只不过JDK提供了一些默认的Collector实现StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); List numList = numStream.collect(Collectors.toList()); Set numSet = numStream.collect(Collectors.toSet()); min
min方法用于计算流内元素的最小值StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); Optional min = numStream.min(Integer::compareTo); max
min方法用于计算流内元素的最大值StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); Optional max = numStream.max(Integer::compareTo); count
count方法用于统计流内元素的总个数StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); //count=6 long count = numStream.count(); anyMatch
anyMatch方法用于匹配校验流内元素是否有符合指定条件的元素StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); //判断是否包含正数,hasPositiveNum=true boolean hasPositiveNum = numStream.anyMatch(num -> num > 0); allMatch
allMatch方法用于匹配校验流内元素是否所有元素都符合指定条件StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); //判断是否全部是正数,allNumPositive=false boolean allNumPositive = numStream.allMatch(num -> num > 0); noneMatch
noneMatch方法用于匹配校验流内元素是否都不符合指定条件StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); //判断是否没有小于0的元素,noNegativeNum=false boolean noNegativeNum = numStream.noneMatch(num -> num < 0); findFirst
findFirst方法用于获取第一个元素,如果流是空的,则返回Optional.emptyStreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); //获取第一个元素,firstNum=-2 Optional firstNum = numStream.findFirst(); findAny
findAny方法用于获取流中的任意一个元素,如果流是空的,则返回Optional.empty,因为可能会使用多线程,所以不保证每次返回的是同一个元素StreamnumStream = Stream.of(-2, -1, 0, 1, 2, 3); Optional anyNum = numStream.findAny();