一、Collection, Collections, collect, Collector, Collectos
Collection是Java集合的祖先接口。Collections是java.util包下的一个工具类,内涵各种处理集合的静态方法。java.util.stream.Stream#collect(java.util.stream.Collector<? superT,A,R>)是Stream的一个函数,负责收集流。java.util.stream.Collector 是一个收集函数的接口,声明了一个收集器的功能。java.util.Collectos则是一个收集器的工具类,内置了一系列收集器实现。二、collect方法
collect,正如其名字显示的,它可以把Stream中的要有元素收集到一个结果容器中(比如Collection)。
collect方法的通用版本
<R> R collect(Supplier<R> supplier,BiConsumer<R, ? super T> accumulator,BiConsumer<R, R> combiner);
先来看看这三个参数的含义:Supplier supplier是一个工厂函数,用来生成一个新的容器;BiConsumer accumulator也是一个函数,用来把Stream中的元素添加到结果容器中;BiConsumer combiner还是一个函数,用来把中间状态的多个结果容器合并成为一个,parallelStream的时候会用到,如果没有实现这个函数,返回结果会缺失很多。
案例
List<Integer> nums = Lists.newArrayList(1,1,null,2,3,4,null,5,6,7,8,9,10);List<Integer> numsWithoutNull = nums.stream().filter(num -> num != null).collect(() -> new ArrayList<Integer>(),(list, item) -> list.add(item),(list1, list2) -> list1.addAll(list2));
使用方法引用,极简化代码
List<Integer> nums = Arrays.asList(1,1,null,2,3,4,null,5,6,7,8,9,10);List<Integer> numsWithoutNull = nums.parallelStream().filter(Objects::nonNull).collect(ArrayList::new, ArrayList::add, ArrayList::addAll);numsWithoutNull.forEach(System.out::println);
上面这段代码就是对一个元素是Integer类型的List,先过滤掉全部的null,然后把剩下的元素收集到一个新的List中。进一步看一下collect方法的三个参数,都是lambda形式的函数(上面的代码可以使用方法引用来简化,留给读者自己去思考)。
第一个函数生成一个新的ArrayList实例;第二个函数接受两个参数,第一个是前面生成的ArrayList对象,二个是stream中包含的元素,函数体就是把stream中的元素加入ArrayList对象中。第二个函数被反复调用直到原stream的元素被消费完毕;第三个函数也是接受两个参数,这两个都是ArrayList类型的,函数体就是把第二个ArrayList全部加入到第一个中;当流是stream时,该参数(函数)不会被调用。
collect方法另外一个override的版本,其依赖[Collector]
<R, A> R collect(Collector<? super T, A, R> collector);
我们可以使用Collectors的toMap、toList、toSet等等静态方法来聚集数据。
三、Collectors
3.1 简介
Collectors 是 Java 8 加入的操作类,位于 java.util.stream 包下。它会根据不同的策略将元素收集归纳起来,比如最简单常用的是将元素装入Map、Set、List 等可变容器中。
Collectors 提供了很多API,有很多都是一些函数的重载,这里我个人将其分为三大类,如下:
数据收集:set、map、list聚合归约:统计、求和、最值、平均、字符串拼接、规约前后处理:分区、分组、自定义操作
3.2 list转换
最常用的方法
List<Integer> nums = Arrays.asList(1,1,null,2,3,4,null,5,6,7,8,9,10);List<Integer> numsWithoutNull = nums.parallelStream().collect(ArrayList::new, ArrayList::add, ArrayList::addAll);numsWithoutNull.forEach(System.out::println);
3.3 set转换
List<Integer> nums = Arrays.asList(1,1,null,2,3,4,null,5,6,7,8,9,10);Set<Integer> set = nums.stream().collect(Collectors.toSet());set.forEach(System.out::println);
3.4 map转换
List<Integer> nums = Arrays.asList(1,1,null,2,3,4,null,5,6,7,8,9,10);Map<String, String> map = nums.stream().collect(Collectors.toMap(s->s+"",v->v+"",(v1,v2)->v1));map.forEach((k,v)->{System.out.println(k+"-"+v);});
3.5 字符串拼接
拼接sql字符串时经常使用,比以前使用StringBuilder时简洁了很多。但是注意,前后缀只会在最前和最后添加,并不是每个字符都会添加,所以能看见我们使用的间隔字符是 ‘,’。
List<Integer> nums = Arrays.asList(1,1,null,2,3,4,null,5,6,7,8,9,10);String sqlstr = nums.stream().map(s->s+"").collect(Collectors.joining("','","('","')"));System.out.println(sqlstr);
执行结果
3.6 分组
分组我们就只举例最近有使用到的一个例子,其他用法没用到就不举例了
List<Integer> nums = Arrays.asList(1,1,2,3,4,5,6,7,8,9,10);Map<Integer,List<Integer>> map = nums.stream().collect(Collectors.groupingBy(s -> s));map.forEach((s,k)->{System.out.println(s+""+k);});