stream Api汇总(java 11)
stream 官方Api文档
前言:
stream是Java8新增的一种处理数据的方式,又称为流。类似sql的数据处理方式来集合运算和表达的处理目标数据。
作用:
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
内部逻辑:
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
设计初衷:
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
集合接口有两个方法来生成流:
- stream() − 为集合创建串行流。
- parallelStream() − 为集合创建并行流。
Stream API
List<String> list = Arrays.asList("abc","abc", "", "bc", "efg", "abcd","", "jkl");
- filter
filter 方法用于通过设置的条件过滤出元素。//将list中空字符串去掉后返回一个新list: List<String> newList = list.stream().filter( i -> !i.isEmpty()).collect(Collectors.toList()); //获取空字符串的数量: long count = list.stream().filter(i -> i.isEmpty()).count();
- map
接收一个有返回值的Function参数,用于映射每个元素到对应的结果。//将list中的每个字符串元素后面加上"a": List<String> newList = list.stream().map( i -> i+"a").collect(Collectors.toList());
- mapToInt/mapToLong/mapToDouble
流转换为数值流
这里可以对mapToInt结果进行转换,用到如下统计结果的收集器: IntSummaryStatistics/DoubleSummaryStatistics/LongSummaryStatistics//转成数值流(IntStream)之后就可以进行数值统计 //但是只有sum返回int,max和min返回OptionalInt,average返回OptionalDouble List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); int i = numbers.stream().mapToInt(x->x).sum();
它们主要用于int、double、long等基本类型上,它们可以用来产生类似如下的统计结果。//int集合相关操作: IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics(); System.out.println("列表中最大的数 : " + stats.getMax()); System.out.println("列表中最小的数 : " + stats.getMin()); System.out.println("所有数之和 : " + stats.getSum()); System.out.println("平均数 : " + stats.getAverage());
- flatMap
对流扁平化处理(比map处理的更细),如分别对List< Map>做流的操作,map的操作单位就是list,而flatMap的操作单位就是map//flatMap常用于合并多个集合,下面这个例子就能说明map和flatMap的区别 Map<String,Object> map1 = new HashMap<>(3); map1.put("name","张三"); map1.put("age",2); map1.put("sex","女"); Map<String,Object> map2 = new HashMap<>(3); map2.put("name","李四"); map2.put("age",2); map2.put("sex","男"); Map<String,Object> map3 = new HashMap<>(3); map3.put("name","王五"); map3.put("age",1); map3.put("sex","女"); List<Map<String,Object>> twoList = new ArrayList<>();//2岁的集合 twoList.add(map1); twoList.add(map2); List<Map<String,Object>> nvList = new ArrayList<>();//女生的集合 nvList.add(map1); nvList.add(map3); //map处理后去重打印后的结果是: //java.util.stream.ReferencePipeline$Head@7a5d012c //java.util.stream.ReferencePipeline$Head@3fb6a447 Stream.of(twoList,nvList).map(Collection::stream).distinct().forEach(System.out::print); //flatMap处理后去重打印后的结果是: //{name=张三, age=2, sex=女} //{name=李四, age=2, sex=男} //{name=王五, age=1, sex=女} Stream.of(twoList,nvList).flatMap(Collection::stream).distinct().forEach(System.out::print);
我看到别人还有关于flatMap更复杂更细的操作,也很实用:
https://blog.csdn.net/weixin_41835612/article/details/83713891.
-
flatMapToInt/flatMapToLong/flatMapToDouble
这个和map的相关操作mapToInt/mapToLong/mapToDouble一样,只不过操作单元更细 -
distinct
去重//list是可重复的集合,用distinct实现去重 list.stream().distinct()
-
sorted
sorted 方法用于对流进行排序。//对list进行正序排序: List<Integer> numbers = Arrays.asList(2, 1, 5, 7, 3 ,4 ,6); numbers.stream().sorted();
排序时用Comparator可自定排序的条件
//对list进行逆序排序: numbers.stream().sorted(Comparator.reverseOrder()); //对这群person按年龄倒序: Person p1= new Person("张三",12,"女"); Person p2= new Person("李四",17,"男"); Person p3= new Person("王五",24,"女"); Stream.of(p1,p2,p3).sorted(Comparator.comparing(Person::getAge).reversed());
-
peek
都是对流的处理,map接收的是Function的参数,而peek和forEach接收的是Consumer的参数,所以map是需要返回值的,peek和forEach却没有返回值。
然后对比peek和forEach,发现foreach会消耗掉流,即终止流操作,而peek不会。举例:Person p1 = new Person("zhangsan",14); Person p2 = new Person("lisi",18); //forEach执行完之后流操作就中止了 Stream.of(p1,p2).forEach(i->i.setAge(100)); Stream.of(p1,p2).forEach(System.out::println); //peek执行完之后还能再继续执行流操作(个人认为功能很鸡肋,主要是不知道这个api的设计理念和运用场景) Stream.of(p1,p2).peek(i->i.setAge(200)).forEach(System.out::println);
-
limit
limit 方法用于获取指定数量的流。//取出list中前三个元素组成新list: List<String> newList = list.stream().limit(3).collect(Collectors.toList());
-
skip
起始索引//将起始索引(第5个)及之后截取固定数量(2个)元素组合新集合: List<Integer> numbers = Arrays.asList(0,1, 2, 3, 4, 5 ,6 ,7); newList = numbers.stream().skip(4).limit(2).collect(Collectors.toList());//[4,5]
-
takeWhile/dropWhile
从开始计算到截止计算的条件//从开始计算,当 n < 3 时就截止: Stream.of(1, 2, 3, 2, 1).takeWhile(n -> n < 3).collect(Collectors.toList());// [1, 2] //一旦 n < 3 不成立就开始计算: Stream.of(1, 2, 3, 2, 1).dropWhile(n -> n < 3).collect(Collectors.toList());// [3, 2, 1]
-
forEach
Stream 提供了新的方法 ‘forEach’ 来迭代流中的每个数据,接收一个无返回值的Consumer参数。//循环打印list的每个元素: list.forEach(System.out::println); list.stream().forEach(System.out::println);
-
forEachOrdered
这个api是用在并行流的,因为并行就意味着顺序不确定,forEachOrdered就用来保证顺序遍历//并行forEach遍历打印顺序是不确定的 list.parallelStream().forEach(System.out::println); //并行forEachOrdered遍历打印顺序是按照list本来的顺序的 list.parallelStream().forEachOrdered(System.out::println);
-
toArray
将流转化成数组//流转化字符串数组 String[] s = Stream.of("a","b").toArray(String[]::new); //流转化对象数组 Person p1 = new Person("zhangsan",14); Person p2 = new Person("lisi",18); Person[] p = Stream.of(p1,p2).toArray(Person[]::new);
-
reduce
对stream类元素进行聚合求值List<Integer> numList = Arrays.asList(1,2,3,4,5); List<String> strList = Arrays.asList("a","b","c","d","e"); numList.stream().reduce((a,b) -> a + b ).get();//15,1+2+3+4+5 numList.stream().reduce((a,b) -> a - b ).get();//-13,1-2-3-4-5 strList.stream().reduce((a,b) -> a + b ).get();//"abcde"
-
collect
主要用于将Stream中的元素通过一定的计算过程转化为另外的表现形式,这里就要提到Collectors这个转化类。Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串。Collectors 官方Api文档Collectors.toList()//将stream流转化成List Collectors.joining()//将stream每个元素拼接形成字符串 Collectors.joining(",")//将stream每个元素拼接形成字符串(中间用逗号隔开) //上面例子我们已经了解到如何转化回集合,下面例子是拼接非空字符串: String str = list.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(","));
-
min/max
按照规则取最大值或最小值//下面例子找出年龄最大的人 Person p1 = new Person("zhangsan",11); Person p2 = new Person("wangwu",18); Person p3 = new Person("lisi",11); Person p = Stream.of(p1,p2,p3).max(Comparator.comparing(Person::getAge)).get(); System.out.println(p);//输出结果:Person(name=wangwu, age=18)(如果找最少是zhangsan)
-
count
返回元素的个数Person p1 = new Person("zhangsan",11); Person p2 = new Person("wangwu",18); Person p3 = new Person("lisi",11); //找到上面三个人中年龄11岁的有几个 int a = (int)Stream.of(p1,p2,p3).filter(i->i.getAge()==11).count(); System.out.println(a);//输出结果:2
-
anyMatch/allMatch/noneMatch
对stream元素作判断时用,传入一个Predicate参数,返回一个boolean类型的判断结果。
anyMatch:当一个或多个元素满足条件返回true。
allMatch:当所有元素满足条件返回true。
noneMatch:当一个或多个元素满足条件返回true。Person p1 = new Person("zhangsan",11); Person p2 = new Person("wangwu",18); Person p3 = new Person("lisi",11); boolean a = Stream.of(p1,p2,p3).allMatch(i->i.getAge()>15);//false,元素全大于15 boolean b = Stream.of(p1,p2,p3).anyMatch(i->i.getAge()>15);//true,有元素大于15 boolean c = Stream.of(p1,p2,p3).noneMatch(i->i.getAge()>15);//false,没有元素大于15
-
findFirst/findAny
findFirst找到steam的第一个元素,findAny找到任意一个。在串行流中,两个返回的都是第一个元素,而在并行流中,findAny返回的元素就不固定了List<String> list = Arrays.asList("a", "b", "c", "d", "e"); String a =list.stream().findFirst().get();//"a" String b =list.stream().findAny().get();//"a" String c =list.parallelStream().findFirst().get();//"a" String d =list.parallelStream().findAny().get();//"c"(随机)
-
(static)builder
创建一个具有生命周期的流构建器,构建一个有序的Stream。
有三个方法:
void accept(T t)
default Stream.Builder add(T t)
Stream build()
官方Api文档 -
(static)empty/of/ofNullable
单个参数构造方法ofNullable/of,ofNullable可为null,of不能null,empty为空stream//新建 Stream.ofNullable("a","b","c","","d"); Stream.of("a","b","c"); Stream.empty();
-
(static)iterate/generate
通过函数的形式生成流//注意下面生成的是无限流,所以用limit控制元素个数 Stream.iterate(0, i -> ++i).limit(5);//0,1,2,3,4 0是初始值 Stream.generate( () -> "a").limit(5);//a,a,a,a,a
-
(static)concat
合并多个streamStream.concat(Stream.of("a","b"), Stream.of("b","c"))//a,b,b,c