示例文件准备
实体类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));