java8 Lambda Stream collect Collectors 常用详细实例 优雅的将一个对象的集合转化成另一个对象的集合
1 2 3 4 List<OrderDetail> orderDetailList = orderDetailService.listOrderDetails(); List<CartDTO> cartDTOList = orderDetailList.stream() .map(e -> new CartDTO(e.getProductId(), e.getProductQuantity())) .collect(Collectors.toList());
交集 (list1 + list2)
1 2 3 List<T> intersect = list1.stream() .filter(list2::contains) .collect(Collectors.toList());
差集
1 2 3 4 5 List<String> reduce1 = list1.stream().filter(item -> !list2.contains(item)).collect(toList()); List<String> reduce2 = list2.stream().filter(item -> !list1.contains(item)).collect(toList());
并集
1 2 3 4 List<String> listAll = list1.parallelStream().collect(toList()); List<String> listAll2 = list2.parallelStream().collect(toList()); listAll.addAll(listAll2);
去重并集
1 2 List<String> listAllDistinct = listAll.stream() .distinct().collect(toList());
从 List 中过滤出一个元素
1 2 User match = users.stream() .filter((user) -> user.getId() == 1 ).findAny().get();
Map 集合转 List
1 2 3 4 5 6 List<Person> list = map.entrySet().stream().sorted(Comparator.comparing(e -> e.getKey())) .map(e -> new Person(e.getKey(), e.getValue())).collect(Collectors.toList()); List<Person> list = map.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getValue)).map(e -> new Person(e.getKey(), e.getValue())).collect(Collectors.toList()); List<Person> list = map.entrySet().stream().sorted(Map.Entry.comparingByKey()).map(e -> new Person(e.getKey(), e.getValue())).collect(Collectors.toList());
Collectors toList
1 2 3 4 5 streamArr.collect(Collectors.toList()); List<Integer> collectList = Stream.of(1 , 2 , 3 , 4 ) .collect(Collectors.toList()); System.out.println("collectList: " + collectList);
Collectors toMap
1 2 3 4 5 6 7 8 9 10 11 map value 为对象 student Map<Integer, Student> map = list.stream().collect(Collectors.toMap(Student::getId, student -> student)); map.forEach((key, value) -> { System.out.println("key: " + key + " value: " + value); }); map value 为对象中的属性 Map<Integer, String> map = list.stream().collect(Collectors.toMap(Student::getId, Student::getName)); map.forEach((key, value) -> { System.out.println("key: " + key + " value: " + value); });
List 集合转 Map
1 2 3 4 5 6 7 8 9 10 Map result = peopleList.stream().collect(Collectors.toMap(p -> p.name, p -> p.age, (k1, k2) -> k1)); Map<Integer, String> result1 = list.stream().collect(Collectors.toMap(Hosting::getId, Hosting::getName)); List<People> peopleList = new ArrayList<>(); peopleList.add(new People("test1" , "111" )); peopleList.add(new People("test2" , "222" )); Map result = peopleList.stream().collect(HashMap::new ,(map,p)->map.put(p.name,p.age),Map::putAll);
List 转 Map<Integer,Apple>
1 2 3 4 5 6 7 8 Map<Integer, Apple> appleMap = appleList.stream().collect(Collectors.toMap(Apple::getId, a -> a,(k1, k2) -> k1));
List 转 List<Map<String,Object>>
1 2 3 4 5 6 7 8 9 10 11 12 13 List<Map<String,Object>> personToMap = peopleList.stream().map((p) -> { Map<String, Object> map = new HashMap<>(); map.put("name" , p.name); map.put("age" , p.age); return map; }).collect(Collectors.toList()); List<Map<String,Object>> personToMap = peopleList.stream().collect(ArrayList::new , (list, p) -> { Map<String, Object> map = new HashMap<>(); map.put("name" , p.name); map.put("age" , p.age); list.add(map); }, List::addAll);
字典查询和数据转换 toMap 时,如果 value 为 null,会报空指针异常 解决办法一:
1 2 Map<String, List<Dict>> resultMaps = Arrays.stream(dictTypes) .collect(Collectors.toMap(i -> i, i -> Optional.ofNullable(dictMap.get(i)).orElse(new ArrayList<>()), (k1, k2) -> k2));
解决办法二:
1 2 Map<String, List<Dict>> resultMaps = Arrays.stream(dictTypes) .filter(i -> dictMap.get(i) != null ).collect(Collectors.toMap(i -> i, dictMap::get, (k1, k2) -> k2));
解决办法三:
1 2 3 Map<String, String> memberMap = list.stream().collect(HashMap::new , (m,v)-> m.put(v.getId(), v.getImgPath()),HashMap::putAll); System.out.println(memberMap);
解决办法四:
1 2 3 4 5 6 7 8 Map<String, String> memberMap = new HashMap<>(); list.forEach((answer) -> memberMap.put(answer.getId(), answer.getImgPath())); System.out.println(memberMap); Map<String, String> memberMap = new HashMap<>(); for (Member member : list) { memberMap.put(member.getId(), member.getImgPath()); }
假设有一个 User 实体类,有方法 getId(),getName(),getAge()等方法,现在想要将 User 类型的流收集到一个 Map 中,示例如下:
1 2 3 Stream<User> userStream = Stream.of(new User(0 , "张三" , 18 ), new User(1 , "张四" , 19 ), new User(2 , "张五" , 19 ), new User(3 , "老张" , 50 )); Map<Integer, User> userMap = userSteam.collect(Collectors.toMap(User::getId, item -> item));
假设要得到按年龄分组的 Map<Integer,List>,可以按这样写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Map<Integer, List<User>> ageMap = userStream.collect(Collectors.toMap(User::getAge, Collections::singletonList, (a, b) -> { List<User> resultList = new ArrayList<>(a); resultList.addAll(b); return resultList; })); Map<Integer, String> map = persons .stream() .collect(Collectors.toMap( p -> p.age, p -> p.name, (name1, name2) -> name1 + ";" + name2)); System.out.println(map);
List<String> 转 String
1 2 3 4 5 6 7 8 9 10 List<String> webs = Arrays.asList("voidcc.com" , "voidmvn.com" , "voidtool.com" ); String allwebs = String.join("," , webs); System.out.println(allwebs); List<String> webs = Arrays.asList("voidcc.com" , "voidmvn.com" , "voidtool.com" ); String allwebs = webs.stream().collect(Collectors.joining("," )); System.out.println(allwebs);
Collectors toSet
1 2 3 4 5 6 7 8 9 10 11 Set<String> result = Stream.of("aa" , "bb" , "cc" , "aa" ).collect(HashSet::new , HashSet::add, HashSet::addAll); Set<String> result2 = Stream.of("aa" , "bb" , "cc" , "aa" ).collect(Collectors.toSet()); Set<Integer> collectSet = Stream.of(1 , 2 , 3 , 4 ).collect(Collectors.toSet()); System.out.println("collectSet: " + collectSet); Stack stack1 = stream.collect(Collectors.toCollection(Stack::new )); String str = stream.collect(Collectors.joining()).toString();
Collectors groupingBy
1 2 Map<Integer, List<User>> ageMap2 = userStream .collect(Collectors.groupingBy(User::getAge));
groupingBy 分组后操作 //Collectors 中还提供了一些对分组后的元素进行 downStream 处理的方法: //counting 方法返回所收集元素的总数; //summing 方法会对元素求和; //maxBy 和 minBy 会接受一个比较器,求最大值,最小值; //mapping 函数会应用到 downstream 结果上,并需要和其他函数配合使用;
1 2 3 4 5 6 7 Map<Integer, Long> sexCount = userStream.collect(Collectors.groupingBy(User::getSex,Collectors.counting())); Map<Integer, Integer> ageCount = userStream.collect(Collectors.groupingBy(User::getSex,Collectors.summingInt(User::getAge))); Map<Integer, Optional<User>> ageMax = userStream.collect(Collectors.groupingBy(User::getSex,Collectors.maxBy(Comparator.comparing(User::getAge)))); Map<Integer, List<String>> nameMap = userStream.collect(Collectors.groupingBy(User::getSex,Collectors.mapping(User::getName,Collectors.toList())));
groupingBy 根据年龄来分组:
1 2 Map<Integer, List> peopleByAge = peoples.stream() .filter(p -> p.age > 12 ).collect(Collectors.groupingBy(p -> p.age, Collectors.toList()));
groupingBy 根据年龄分组,年龄对应的键值 List 存储的为 Person 的姓名:
1 2 3 Map<Integer, List> peopleByAge = people.stream() .collect(Collectors.groupingBy(p -> p.age, Collectors.mapping((Person p) -> p.name, Collectors.toList())));
groupingBy 根据姓名分组,获取每个姓名下人的年龄总和:
1 2 3 Map sumAgeByName = peoples.stream().collect(Collectors.groupingBy(p -> p.name, Collectors.reducing(0 , (Person p) -> p.age, Integer::sum))); sumAgeByName = peoples.stream().collect(Collectors.groupingBy(p -> p.name, Collectors.summingInt((Person p) -> p.age)));
groupingBy Boolean 分组:
1 2 3 4 5 Map<Boolean, List<Integer>> collectGroup = Stream.of(1 , 2 , 3 , 4 ) .collect(Collectors.groupingBy(it -> it > 3 )); System.out.println("collectGroup : " + collectGroup);
groupingBy 按年龄分组
1 2 3 4 5 Map<Integer, List<Person>> personsByAge = persons.stream().collect(Collectors.groupingBy(p -> p.age)); personsByAge.forEach((age, p) -> System.out.format("age %s: %s\n" , age, p));
Collectors partitioningBy Collectors 中还提供了 partitioningBy 方法,接受一个 Predicate 函数,该函数返回 boolean 值,用于将内容分为两组。假设 User 实体中包含性别信息 getSex(),可以按如下写法将 userStream 按性别分组:
1 2 Map<Boolean, List<User>> sexMap = userStream .collect(Collectors.partitioningBy(item -> item.getSex() > 0 ));
可以看到 Java8 的分组功能相当强大,当然你还可以完成更复杂的功能。另外 Collectors 中还存在一个类似 groupingBy 的方法:partitioningBy,它们的区别是 partitioningBy 为键值为 Boolean 类型的 groupingBy,这种情况下它比 groupingBy 更有效率。 partitioningBy 将数字的 Stream 分解成奇数集合和偶数集合。
1 2 3 4 5 Map<Boolean, List<Integer>> collectParti = Stream.of(1 , 2 , 3 , 4 ) .collect(Collectors.partitioningBy(it -> it % 2 == 0 )); System.out.println("collectParti : " + collectParti);
Collectors joining Collectors.joining 收集 Stream 中的值,该方法可以方便地将 Stream 得到一个字符串。joining 函数接受三个参数,分别表示允(用以分隔元素)、前缀和后缀:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 String names = peoples.stream().map(p->p.name).collect(Collectors.joining("," )) String strJoin = Stream.of("1" , "2" , "3" , "4" ) .collect(Collectors.joining("," , "[" , "]" )); System.out.println("strJoin: " + strJoin); String phrase = persons .stream() .filter(p -> p.age >= 18 ) .map(p -> p.name) .collect(Collectors.joining(" and " , "In Germany " , " are of legal age." )); System.out.println(phrase);
组合 Collectors:
1 2 3 4 5 6 Map<Boolean, Long> partiCount = Stream.of(1 , 2 , 3 , 4 ) .collect(Collectors.partitioningBy(it -> it.intValue() % 2 == 0 , Collectors.counting())); System.out.println("partiCount: " + partiCount);
Collectors 分别提供了求平均值 averaging、总数 couting、最小值 minBy、最大值 maxBy、求和 suming 等操作。但是假如你希望将流中结果聚合为一个总和、平均值、最大值、最小值,那么 Collectors.summarizing(Int/Long/Double)就是为你准备的,它可以一次行获取前面的所有结果,其返回值为(Int/Long/Double)SummaryStatistics。
1 2 3 4 5 6 7 8 9 10 11 12 13 DoubleSummaryStatistics dss = people.collect(Collectors.summarizingDouble((Person p)->p.age)); double average=dss.getAverage();double max=dss.getMax();double min=dss.getMin();double sum=dss.getSum();double count=dss.getCount();IntSummaryStatistics ageSummary = persons .stream() .collect(Collectors.summarizingInt(p -> p.age)); System.out.println(ageSummary);
使用 collect 可以将 Stream 转换成值。maxBy 和 minBy 允许用户按照某个特定的顺序生成一个值。 averagingDouble:求平均值,Stream 的元素类型为 double averagingInt:求平均值,Stream 的元素类型为 int averagingLong:求平均值,Stream 的元素类型为 long counting:Stream 的元素个数 maxBy:在指定条件下的,Stream 的最大元素 minBy:在指定条件下的,Stream 的最小元素 reducing: reduce 操作 summarizingDouble:统计 Stream 的数据(double)状态,其中包括 count,min,max,sum 和平均。 summarizingInt:统计 Stream 的数据(int)状态,其中包括 count,min,max,sum 和平均。 summarizingLong:统计 Stream 的数据(long)状态,其中包括 count,min,max,sum 和平均。 summingDouble:求和,Stream 的元素类型为 double summingInt:求和,Stream 的元素类型为 int summingLong:求和,Stream 的元素类型为 long
1 2 3 4 5 Optional<Integer> collectMaxBy = Stream.of(1 , 2 , 3 , 4 ) .collect(Collectors.maxBy(Comparator.comparingInt(o -> o))); System.out.println("collectMaxBy:" + collectMaxBy.get());
Collectors averagingInt 计算集合的平均年龄
1 2 3 4 5 Double averageAge = persons .stream() .collect(Collectors.averagingInt(p -> p.age)); System.out.println(averageAge);
自定义 Collector
1 2 3 4 5 6 7 8 9 10 11 12 Collector<Person, StringJoiner, String> personNameCollector = Collector.of( () -> new StringJoiner(" | " ), (j, p) -> j.add(p.name.toUpperCase()), (j1, j2) -> j1.merge(j2), StringJoiner::toString); String names = persons .stream() .collect(personNameCollector); System.out.println(names);