Stream操作时Collectors工具类中常用方法

示例文件准备

实体类User :

@Data
public class User {
    private String userId;
    private String name;
    private String address;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
    private Date createTime;
    private int age;
    private Long uuid;

}

测试main方法制作数据 :

public static void main(String[] args) throws Exception{
        SimpleDateFormat sdf  = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));

        User user1 = new User();
        user1.setUserId("11");
        user1.setAddress("地址11");
        user1.setName("姓名11");
        user1.setCreateTime(sdf.parse("2020-07-09 21:12:45"));
        user1.setAge(20);

        User user2 = new User();
        user2.setUserId("22");
        user2.setAddress("地址22");
        user2.setName("姓名22");
        user2.setCreateTime(sdf.parse("2020-08-09 21:12:45"));
        user2.setAge(21);

        User user3 = new User();
        user3.setUserId("33");
        user3.setAddress("地址33");
        user3.setName("姓名33");
        user3.setCreateTime(sdf.parse("2020-07-10 21:12:45"));
        user3.setAge(30);

        User user4 = new User();
        user4.setUserId("44");
        user4.setAddress("地址44");
        user4.setName("姓名44");
        user4.setAge(20);

        User user5 = new User();
        user5.setUserId("55");
        user5.setAddress("地址55");
        user5.setName("姓名55");
        user5.setAge(40);

        User user6 = new User();
        user6.setUserId("66");
        user6.setAddress("地址66");
        user6.setName("姓名11");
        user6.setCreateTime(sdf.parse("2016-01-10 21:12:45"));
        user6.setAge(10);

        User user7 = new User();
        user7.setUserId("11");
        user7.setAddress("地址77777");
        user7.setName("姓名11");
        //  user7.setCreateTime(sdf.parse("2020-01-10 21:12:45"));
        user7.setAge(26);

        User user8 = new User();
        user8.setUserId("11");
        user8.setAddress("地址8888");
        user8.setName("姓名11");
        // user8.setCreateTime(sdf.parse("2020-05-10 21:12:45"));

        List<User> list1 = new ArrayList<>();
        list1.add(user1);
        list1.add(user2);
        list1.add(user3);
        list1.add(user4);
        list1.add(user6);
        list1.add(user7);
        list1.add(user8);
}

聚合与分组

toList、toSet、toCollection

描述:将聚合之后的元素,重新封装到队列中,然后返回
返回类型:List<T>和Set<T>和Collection<T>

//输出结果  [姓名11, 姓名22, 姓名33, 姓名44, 姓名11, 姓名11, 姓名11]
List<String> aa = list1.stream().map(User::getName).collect(Collectors.toList());
//输出结果  [姓名11, 姓名22, 姓名33, 姓名44]
Set<String> aa1 = list1.stream().map(User::getName).collect(Collectors.toSet());
//输出结果  [姓名11, 姓名22, 姓名33, 姓名44]
Collection<String> aa2 = list1.stream().map(User::getName).collect(Collectors.toCollection(TreeSet::new));

toMap、toConcurrentMap

描述:这两个方法的作用是将聚合元素,重新组装为Map结构,也就是 k-v 结构。两者用法一样,区别是toMap返回的是Map,toConcurrentMap返回ConcurrentMap,也就是说,toConcurrentMap返回的是线程安全的 Map 结构【toMap结果是 1:1 的 k-v 结构】

返回类型:Map<K,V>

//输出结果  {66=User(userId=66, name=姓名11, address=地址66, createTime=Sun Jan 10 21:12:45 CST 2016, age=10, uuid=null)XXXXXX数据太多了}
//得到根据id分组后数据
Map<String, User> map2 = list1.stream()
                .collect(Collectors.toMap(User::getUserId, Function.identity(), (x, y) -> x));

//输出结果  {66=姓名11, 44=姓名44, 33=姓名33, 22=姓名22, 11=姓名11}
//得到根据id分组后的姓名
Map<String, String > map3 = list1.stream()
                .collect(Collectors.toMap(User::getUserId, User::getName, (x, y) -> x));

groupingBy、groupingByConcurrent

描述:groupingBy与toMap都是将聚合元素进行分组,区别是,toMap结果是 1:1 的 k-v 结构,groupingBy的结果是 1:n 的 k-v 结构。

返回类型:Map<K,T<T>>

//输出结果 {0=[User(userId=11, name=姓名11, address=地址8888, createTime=null, age=0, uuid=null)], 20=[User(userId=11, name=姓名11, address=地址11, createTime=Thu Jul 09 21:12:45 CST 2020, age=20, uuid=null), User(userId=44, name=姓名44, address=地址44, createTime=null, age=20, uuid=null)], 21=[User(userId=22, name=姓名22, address=地址22, createTime=Sun Aug 09 21:12:45 CST 2020, age=21, uuid=null)], 26=[User(userId=11, name=姓名11, address=地址77777, createTime=null, age=26, uuid=null)], 10=[User(userId=66, name=姓名11, address=地址66, createTime=Sun Jan 10 21:12:45 CST 2016, age=10, uuid=null)], 30=[User(userId=33, name=姓名33, address=地址33, createTime=Fri Jul 10 21:12:45 CST 2020, age=30, uuid=null)]}
//得到根据age分组后数据
Map<Integer, List<User>> map5 = list1.stream().collect(Collectors.groupingBy(User::getAge));

//输出结果  {0=[User(userId=11, name=姓名11, address=地址8888, createTime=null, age=0, uuid=null)], 20=[User(userId=11, name=姓名11, address=地址11, createTime=Thu Jul 09 21:12:45 CST 2020, age=20, uuid=null), User(userId=44, name=姓名44, address=地址44, createTime=null, age=20, uuid=null)], 21=[User(userId=22, name=姓名22, address=地址22, createTime=Sun Aug 09 21:12:45 CST 2020, age=21, uuid=null)], 26=[User(userId=11, name=姓名11, address=地址77777, createTime=null, age=26, uuid=null)], 10=[User(userId=66, name=姓名11, address=地址66, createTime=Sun Jan 10 21:12:45 CST 2016, age=10, uuid=null)], 30=[User(userId=33, name=姓名33, address=地址33, createTime=Fri Jul 10 21:12:45 CST 2020, age=30, uuid=null)]}
//得到根据age分组后数据
Map<Integer, Set<User>> map6 = list1.stream().collect(Collectors.groupingBy(User::getAge, Collectors.toSet()));


既然groupingBy也是分组,是不是也能够实现与toMap类似的功能,比如,根据 id 分组

//输出结果 {66=User(userId=66, name=姓名11, address=地址66, createTime=Sun Jan 10 21:12:45 CST 2016, age=10, uuid=null), 44=User(userId=44, name=姓名44, address=地址44, createTime=null, age=20, uuid=null), 33=User(userId=33, name=姓名33, address=地址33, createTime=Fri Jul 10 21:12:45 CST 2020, age=30, uuid=null), 22=User(userId=22, name=姓名22, address=地址22, createTime=Sun Aug 09 21:12:45 CST 2020, age=21, uuid=null), 11=User(userId=11, name=姓名11, address=地址11, createTime=Thu Jul 09 21:12:45 CST 2020, age=20, uuid=null)}
//与上面的 map2 结果是相同的
 Map<String, Object> map7 = list1.stream()
                .collect(Collectors.groupingBy(User::getUserId, Collectors.collectingAndThen(Collectors.toList(), list -> list.get(0))));

想要线程安全的Map,可以使用groupingByConcurrent

partitioningBy

描述:partitioningBy与groupingBy的区别在于,partitioningBy借助Predicate断言,可以将集合元素分为true和false两部分

返回类型:Map<Boolean,T<T>>

//输出结果  {false=[User(userId=66, name=姓名11, address=地址66, createTime=Sun Jan 10 21:12:45 CST 2016, age=10, uuid=null), User(userId=11, name=姓名11, address=地址8888, createTime=null, age=0, uuid=null)], true=[User(userId=11, name=姓名11, address=地址11, createTime=Thu Jul 09 21:12:45 CST 2020, age=20, uuid=null), User(userId=22, name=姓名22, address=地址22, createTime=Sun Aug 09 21:12:45 CST 2020, age=21, uuid=null), User(userId=33, name=姓名33, address=地址33, createTime=Fri Jul 10 21:12:45 CST 2020, age=30, uuid=null), User(userId=44, name=姓名44, address=地址44, createTime=null, age=20, uuid=null), User(userId=11, name=姓名11, address=地址77777, createTime=null, age=26, uuid=null)]}
//按照年龄是否大于11岁 分组
Map<Boolean, List<User>> map8 = list1.stream().collect(Collectors.partitioningBy(s -> s.getAge() > 11));
  
//输出结果   {false=[User(userId=11, name=姓名11, address=地址8888, createTime=null, age=0, uuid=null), User(userId=66, name=姓名11, address=地址66, createTime=Sun Jan 10 21:12:45 CST 2016, age=10, uuid=null)], true=[User(userId=11, name=姓名11, address=地址11, createTime=Thu Jul 09 21:12:45 CST 2020, age=20, uuid=null), User(userId=11, name=姓名11, address=地址77777, createTime=null, age=26, uuid=null), User(userId=33, name=姓名33, address=地址33, createTime=Fri Jul 10 21:12:45 CST 2020, age=30, uuid=null), User(userId=22, name=姓名22, address=地址22, createTime=Sun Aug 09 21:12:45 CST 2020, age=21, uuid=null), User(userId=44, name=姓名44, address=地址44, createTime=null, age=20, uuid=null)]}
//按照年龄是否大于11岁 分组
Map<Boolean, Set<User>> map9 = list1.stream().collect(Collectors.partitioningBy(s -> s.getAge() > 11, Collectors.toSet()));

数据连接

joining

描述:对String类型的元素进行聚合,拼接成一个字符串返回,作用与java.lang.String#join类似,提供了 3 个不同重载方法,可以实现不同的需要

返回类型:String

//输出结果  java张三李四
String q = Stream.of("java", "张三", "李四").collect(Collectors.joining());
        
//输出结果  java, 张三, 李四
String w =Stream.of("java", "张三", "李四").collect(Collectors.joining(", "));

//输出结果  【java, 张三, 李四】
String t =Stream.of("java", "张三", "李四").collect(Collectors.joining(", ", "【", "】"));

操作链

collectingAndThen

描述:它是先对集合进行一次聚合操作,然后通过Function定义的函数,对聚合后的结果再次处理。

返回类型:Map<K,V>
示例也可以查看这个:collectingAndThen的应用例子

//输出结果  [{"address":"地址44","age":20,"name":"姓名44","userId":"44"},{"address":"地址33","age":30,"createTime":1594386765000,"name":"姓名33","userId":"33"},{"address":"地址22","age":21,"createTime":1596978765000,"name":"姓名22","userId":"22"},{"address":"地址8888","age":0,"name":"姓名11","userId":"11"}]
//取出name相同的人中年龄最小的一个人
Map<String, User> collect = list1.stream().collect(
                Collectors.groupingBy(User::getName,
                        Collectors.collectingAndThen(Collectors.reducing((c1, c2) -> c1.getAge()< c1.getAge() ? c1 : c2),
                                Optional::get)));
        List<User> list6  = new ArrayList<>(collect.values());

先操作后聚合

mapping

描述:mapping先通过Function函数处理数据,然后通过Collector方法聚合元素

返回类型:T

//输出结果 [姓名11, 姓名22, 姓名33, 姓名44, 姓名11, 姓名11, 姓名11]
//获取name列表
List<String> list8= list1.stream()
                .collect(Collectors.mapping(User::getName, Collectors.toList()));
        System.out.println(list8);

先聚合后操作

reducing

描述: reducing提供了 3 个重载方法:
示例也可以查看这个:reducing的使用例子

//:直接通过BinaryOperator操作,返回值是Optional
public static <T> Collector<T, ?, Optional<T>> reducing(BinaryOperator<T> op)

//:预定默认值,然后通过BinaryOperator操作
public static <T> Collector<T, ?, T> reducing(T identity, BinaryOperator<T> op)

//:预定默认值,通过Function操作元素,然后通过BinaryOperator操作
public static <T, U> Collector<T, ?, U> reducing(U identity, Function<? super T, ? extends U> mapper, BinaryOperator<U> op)
 //输出结果 Optional[127]
 //计算用户的age总和
 Optional<Integer> te = list1.stream()
                .map(User::getAge)
                .collect(Collectors.reducing(Integer::sum));

数据统计

counting

描述:统计元素列表的数量
返回类型:Long

Long a = list1.stream().collect(Collectors.counting());

averagingDouble、averagingInt、averagingLong

描述:统计元素列表的平均值
返回类型:3种方法都是Double

Double b = list1.stream().collect(Collectors.averagingInt(User::getAge));

summingDouble、summingInt、summingLong

描述:统计元素列表的和
返回类型:summingDouble返回的是Double类型、summingInt返回的是Integer类型,summingLong返回的是Long类型。

//输出结果  127
int c = list1.stream().collect(Collectors.summingInt(User::getAge));

maxBy、minBy

描述:统计元素列表的最大值/最小值
返回类型:Optional<T>

Optional<User> d = list1.stream().collect(Collectors.minBy(Comparator.comparing(User::getAge)));

Optional<User> e = list1.stream().collect(Collectors.maxBy(Comparator.comparing(User::getAge)));

summarizingDouble、summarizingInt、summarizingLong

描述:统计元素列表的和
返回类型:summarizingDouble返回DoubleSummaryStatistics类型,summarizingInt返回IntSummaryStatistics类型,summarizingLong返回LongSummaryStatistics类型。

//输出结果  IntSummaryStatistics{count=7, sum=127, min=0, average=18.142857, max=30}
IntSummaryStatistics f = list1.stream().collect(Collectors.summarizingInt(User::getAge));
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值