Stream中的常用操作详解
java8 Stream中的常用操作
一. 匹配、过滤、筛选操作
- 以下操作的入参数都是Predicate[核心是输入一个值,返回一个布尔值(true or false)].
- 流的中间操作和终止操作,简单理解就是终止操作之后返回的不是流对象(其他对象或没有返回值),中间操作返回的都是流对象(Stream
)。 - 具体的操作案例
-
filter: 是一种流的中间操作
List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php"); stringList.stream() .filter(x -> x.length() > 3) .forEach(System.out::println);
-
anyMatch 是一种流的终止操作,与此用法相同的还有一个allMatch 和noneMatch,也是终止操作,区别是allMatch是所有匹配才返回true,anyMath是只要有一个匹配就返回true, noneMatch 是没有匹配到返回true。
List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php"); boolean match = stringList.stream().anyMatch(x -> x.contains("c")); System.out.println(match); boolean allMatch = stringList.stream().allMatch(x -> x.contains("c")); System.out.println(allMatch); boolean noMatch = stringList.stream().allMatch(x -> x.contains("c")); System.out.println(noMatch);
-
dropWhile: 删除当前流中符号条件的数据,直到不满足条件为止,即从流中的第一个元素开始匹配,如果满足则继续匹配,如果不满足就不会再继续象后匹配。
List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php"); stringList.stream() //匹配第一个元素是满足条件的,第二个不满足条件,后续就算是满足条件的也不会被删除 .dropWhile(x -> x.length() < 5) .forEach(System.out::println); stringList.stream() //匹配第一个元素是不满足条件的,后续就算是满足条件的也不会被删除 .dropWhile(x -> x.length() < 3) .forEach(System.out::println);
-
takeWhile 与dropWhile类似,只是takeWhile是取出来元素生成新的流,dropWhile是删除匹配的元素,用剩下的元素生成一个新的流
List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php"); stringList.stream() //匹配时前两个满足,第三个不满足就会终止,即只取到前面两个元素 .takeWhile(x -> x.length() > 2) .forEach(System.out::println);
二. map相关操作
- map操作传入的参数是Function[核心是输入一个参数,返回一个值],map也是流的中间操作,map结果是一个新流
- 如果结果为空,则返回空流(empty stream)
- 具体的操作案例
- map
List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php");
stringList.stream()
.filter(x -> x.length() > 3)
.map(String::length)
.forEach(System.out::println);
//- mapToInt 即通过一个ToIntFunction,返回一个IntStream
//- mapToDouble 即通过一个ToDoubleFunction,返回一个DoubleStream
//- mapToLong 即通过一个ToLongFunction,返回一个LongStream
- flatmap
List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php");
stringList.stream()
.flatMap(x -> Stream.of(x.split("")))
.forEach(System.out::println);
//- flatMapToInt 即通过一个Function,返回一个IntStream
//- flatMapToDouble 即通过一个Function,返回一个DoubleStream
//- flatMapToLong 即通过一个Function,返回一个LongStream
三.排序、最值、去重操作
-
排序有两个方法,sorted()和sorted(Comparator<? super T> comparator),前者是默认排序,后者是按特定的比较器实现排序,排序也是一种中间操作
-
max和min是两个求最值的操作,是一种流的终止操作,返回的是一个最值得Optional
-
去重是distinct操作,也是中间操作
-
案例:
- sorted
//sorted List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php"); stringList.stream() .sorted() .forEach(System.out::println); //特定比较器排序 stringList.stream() //Comparator.comparingInt(String::length) 等价于lambada表达式:(x,y) -> x.length() - y.length() .sorted(Comparator.comparingInt(String::length)) .forEach(System.out::println);
- max、min 都是传入一个比较器,返回一个对应得Optional
List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php"); String val = stringList.stream() //换成min也同理 .max(Comparator.comparingInt(String::length)) .orElse(null); System.out.println(val);
- distinct
List<String> strList = List.of("java","pathon", "go", "c++", "c#", "php", "java", "go"); strList.stream().distinct().forEach(System.out::println);
四. 数量相关操作
-
计数操作:count终止操作,返回的是当前流中的元素个数
-
跳过操作:skip 中间操作,返回当前流中跳过指定元素个数后剩下的元素组成的新流
-
取数操作:limit 中间操作,返回当前流中前n个元素组成的新的流,n为正整数 是limit函数的参数
-
案例
-
count
List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php"); long count = stringList.stream().filter(x -> x.length() > 3).count(); System.out.println(count);
-
skip
List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php"); stringList.stream().skip(2).forEach(System.out::println);
-
limit
List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php"); stringList.stream().limit(2).forEach(System.out::println);
-
五.查找操作(findAny和findFirst)
-
查找操作都属于终止操作,都无入参
-
一般搭配筛选和过滤等中间操作
-
案例
-
findFirst
List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php"); String val = stringList.stream() .findFirst() .orElse(null); System.out.println(val); //搭配filter,sorted String value = stringList.stream() .filter(x -> x.length() > 2) .sorted() .findFirst() .orElse(null); System.out.println(value);
-
findAny
List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php"); String val = stringList.stream() .findAny() .orElse(null); System.out.println(val); //搭配filter,sorted String value = stringList.stream() .filter(x -> x.length() > 2) .sorted() .findAny() .orElse(null); System.out.println(value);
-
六.遍历操作(peek和foreach)
-
peek是中间操作,一般用于程序调试,最终结果是一个流对象
-
foreach是终止操作,无返回值
-
案例
List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php"); stringList.stream() .peek(System.out::println) .filter(x -> x.length() > 4) .forEach(System.out::println);
七. collect操作
-
collect操作有两个方法,一个是collect(Collector<? super T, A, R> collector), 一个是collect(Supplier
supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner)。 -
Collector<? super T, A, R> collector 是一个接口,该接口对应方法有以下几个
-
Supplier supplier(); 即生成一个类型为A的可变容器
-
BiConsumer<A, T> accumulator(); 可变容器的具体操作
-
BinaryOperator combiner(); 合并函数
-
Function<A, R> finisher(); 最终结果转换函数
-
-
常用操作案例
List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php"); //toList List<String> list = stringList.stream() .filter(x -> x.length() > 4) .collect(Collectors.toList()); //toSet Set<String> set = stringList.stream() .filter(x -> x.length() > 4) .collect(Collectors.toSet()); //toMap Map<String, Integer> map = stringList.stream() .filter(x -> x.length() > 4) .collect(Collectors.toMap(x -> x, String::length)); //joining String str = stringList.stream() .filter(x -> x.length() > 4) .collect(Collectors.joining(",")); String str2 = stringList.stream() .filter(x -> x.length() > 4) .collect(Collectors.joining(",","{","}")); //groupingBy List<String> strList = List.of("java","pathon", "go", "c++", "c#", "php", "java", "go"); Map<String, List<String>> listMap = strList.stream() .collect(Collectors.groupingBy(x -> x)); //partitioningBy List<String> strList = List.of("java","pathon", "go", "c", "c", "php", "java", "go"); Map<Boolean, List<String>> booleanListMap =strList.stream() .collect(Collectors.partitioningBy(x -> x.contains("c"))); //一般操作 即用指定的函数实现Collectors操作 List<String> strList = List.of("java","pathon", "go", "c", "c", "php", "java", "go"); List<String> list = strList.stream() .distinct() .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
八. reduce操作
-
reduce 操作实现的是从通过当前流中元素根据指定的计算生成一个新的值,计算可以是count、min和max等方法,概念比较抽象,多练习。
-
reduce和collect一样都有一般操作,两者类似,就是按照对应的接口实现来完成相应的操作。
-
常用案例
// 用reduce(BinaryOperator<T> accumulator) BinaryOperator是传入两个相同的值,返回一个跟入参类型一样的值,此方法返回的是Optional List<String> strList = List.of("java","pathon", "go", "c", "c", "php", "java", "go"); String reduce = strList.stream().reduce((x, y) -> x + y).orElse(""); //用reduce(T identity, BinaryOperator<T> accumulator) 此方法返回指定类型T的值,即在指定类型T,值为identity的基础上进行对应的操作后得到的结果,BinaryOperator是输入两个入参类型都为T,返回值也为T String reduce1 = strList.stream().reduce("@@@", (x, y) -> x + y); //用reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner) 此方法返回的是指定类型U的值,BiFunction<U, ? super T, U> 其核心为输入两个值U,T,返回的是入参中的U int reduce2 = strList.stream() .reduce(0, (x, y) -> x + y.length(), Integer::sum);
stream的创建见之前的基础篇,后续再详解函数式编程接口,这块内容后续也会涉及Flux,Spring Web Flux。