简介

在java stream中的collect方法中需要使用Collectors作为参数,这一个非常强大的功能。如:

一、数据转换

我们可以将对应的数据使用流通过collect转换为我们需要的数据集合如:

  • toCollection(Supplier<Collection<T>> collectionSupplier): 将流中的元素收集到给定的集合中。
  • toList(): 将流中的元素收集到 List 中。
  • toSet(): 将流中的元素收集到 Set 中,自动去重。
  • toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends V> valueMapper): 将流中的元素收集到 Map 中,需要提供键和值的映射函数,第一个参数是keyMapper,第二个参数是valueMapper。
// 示例数据:一个包含字符串的列表
        List<String> words = Arrays.asList("apple", "banana", "apple", "orange", "banana", "banana");

        // 示例数据:一个包含Person对象的列表
        List<Person> people = Arrays.asList(
            new Person("Alice", 30, "New York"),
            new Person("Bob", 25, "Los Angeles"),
            new Person("Charlie", 35, "Chicago"),
            new Person("David", 30, "New York"),
            new Person("Emily", 28, "Los Angeles")
        );

1、toCollection将收集到的数据给到指定的集合是通过参数进行设置,如:

LinkedList<String> wordsLinkedList = words.stream()
                                                  .collect(Collectors.toCollection(LinkedList::new));

上面的例子,我们转换成了LinkedList。

2、toList()将stream转换为list。这里转换的list是ArrayList,如:

 List<String> result = list.stream().collect(Collectors.toList());

3、 toSet()将Stream转换成为set。这里转换的是HashSet,注意set中是没有重复的元素,也就是说它会自动的去重,如:

Set<String> wordsSet = words.stream().collect(Collectors.toSet());

4、toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends V> valueMapper),将流中的元素收集到 Map 中,如:

Map<String, Integer> map = list.stream()
            .collect(Collectors.toMap(String::toString, String::length));

如果stream中有重复的值,则转换会报IllegalStateException异常 ,解决如下:

// 提供一个合并函数来处理键冲突
        // 在这个例子中,如果键冲突,我们选择保留较大的年龄值
        Map<String, Integer> nameToAgeWithMerge = people.stream()
            .collect(Collectors.toMap(
                Person::getName,       // 键提取函数
                Person::getAge,        // 值提取函数
                (existingValue, newValue) -> Math.max(existingValue, newValue) // 合并函数
            ));
        
        // 提供一个合并函数,选择保留较新的值
        Map<String, Integer> nameToAgeWithMergeNew = people.stream()
            .collect(Collectors.toMap(
                Person::getName,       // 键提取函数
                Person::getAge,        // 值提取函数
                (existingValue, newValue) -> newValue // 合并函数
            ));
        

        // 提供一个合并函数,选择保留旧的值
        Map<String, Integer> nameToAgeWithMergeOld = people.stream()
            .collect(Collectors.toMap(
                Person::getName,       // 键提取函数
                Person::getAge,        // 值提取函数
                (existingValue, newValue) -> existingValue // 合并函数
            ));

二、聚合

聚合操作通常使用 Collectors 提供的各种聚合方法,如

  • summingInt():计算总和
  • averagingInt():计算平均值
  • joining():字符串拼接
  • counting():统计元素格个数

1、summingInt()主要用来计算数据的总和,如:

int sum = numbers.stream()
                         .collect(Collectors.summingInt(Integer::intValue));

2、averagingInt()对stream中的元素做平均,如: 

double average = numbers.stream()
                                .collect(Collectors.averagingInt(Integer::intValue));

3、joining()用来连接stream中的元素,其中它会有三种使用方式,如 :

(1)无参数

List<String> words = Arrays.asList("apple", "banana", "cherry");

        // 无参数的 joining()
        String joined = words.stream()
                             .collect(Collectors.joining());
        System.out.println("Joined string: " + joined); // 输出:applebananacherry

(2 )一个参数,以“,”为每个元素间隔进行拼接

// 带一个参数的 joining()
        String joinedWithDelimiter = words.stream()
                                          .collect(Collectors.joining(", "));
        System.out.println("Joined string with delimiter: " + joinedWithDelimiter); // 输出:apple, banana, cherry

(3)三个参数,第1个参数以“,”为每个元素间隔进行拼接,第2,3个分别为前缀后缀

/ 带三个参数的 joining()
        String joinedWithDelimiterPrefixSuffix = words.stream()
                                                      .collect(Collectors.joining(", ", "[", "]"));
        System.out.println("Joined string with delimiter, prefix, and suffix: " + joinedWithDelimiterPrefixSuffix); // 输出:[apple, banana, cherry]

 4、counting()主要用来统计stream中元素的个数:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // 统计流中元素的总数
        long count = numbers.stream()
                            .collect(Collectors.counting());
        System.out.println("Total count: " + count);

三、分组 

分组操作通常使用 Collectors.groupingBy() 方法,它允许你根据某个条件将流中的元素分组为键值对结构。

import java.util.*;
import java.util.stream.*;
import java.util.stream.Collectors;

public class GroupingExample {
    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
            new Person("Alice", 30, "New York"),
            new Person("Bob", 25, "Los Angeles"),
            new Person("Charlie", 35, "New York"),
            new Person("David", 30, "Chicago"),
            new Person("Emily", 28, "Los Angeles")
        );

        // 按城市分组
        Map<String, List<Person>> peopleByCity = people.stream()
                                                       .collect(Collectors.groupingBy(Person::getCity));
        System.out.println("People grouped by City: " + peopleByCity);

        // 按年龄分组并计算每个组的人数
        Map<Integer, Long> peopleCountByAge = people.stream()
                                                    .collect(Collectors.groupingBy(Person::getAge, Collectors.counting()));
        System.out.println("People count by Age: " + peopleCountByAge);

        // 按城市和年龄分组
        Map<String, Map<Integer, List<Person>>> peopleByCityAndAge = people.stream()
            .collect(Collectors.groupingBy(Person::getCity, 
                                          Collectors.groupingBy(Person::getAge)));
        System.out.println("People grouped by City and Age:");
        peopleByCityAndAge.forEach((city, ageMap) -> {
            System.out.println("City: " + city);
            ageMap.forEach((age, peopleList) -> {
                System.out.println("  Age: " + age + " - " + peopleList);
            });
        });
    }
}

Collectors.partitioningBy()是一个特别的groupingBy,PartitioningBy返回一个Map,这个Map是以boolean值为key,从而将stream分成两部分,一部分是匹配PartitioningBy条件的,一部分是不满足条件的,如:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // 根据是否为偶数进行分区
        Map<Boolean, List<Integer>> partitionedNumbers = numbers.stream()
                                                                .collect(Collectors.partitioningBy(n -> n % 2 == 0));
        System.out.println("Partitioned Numbers: " + partitionedNumbers);

四、collectingAndThen()

collectingAndThen它允许你对流中的元素进行收集操作后,再对收集的结果进行进一步的处理,如:将流中的元素收集到一个集合后进行排序

import java.util.*;
import java.util.stream.*;
import java.util.stream.Collectors;

public class CollectingAndThenExample1 {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5);

        // 将流中的元素收集到一个列表后进行排序
        List<Integer> sortedNumbers = numbers.stream()
            .collect(Collectors.collectingAndThen(Collectors.toList(), List::sort));
        System.out.println("Sorted Numbers: " + sortedNumbers);
    }
}

 如:将流中的元素收集到一个集合后进行去重

import java.util.*;
import java.util.stream.*;
import java.util.stream.Collectors;

public class CollectingAndThenExample2 {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5);

        // 将流中的元素收集到一个集合后进行去重
        Set<Integer> uniqueNumbers = numbers.stream()
            .collect(Collectors.collectingAndThen(Collectors.toSet(), Set::stream)
                .mapToInt(Integer::intValue)
                .boxed()
                .collect(Collectors.toSet()));
        System.out.println("Unique Numbers: " + uniqueNumbers);
    }
}

如:将流中的对象收集到一个集合后进行过滤 

import java.util.*;
import java.util.stream.*;
import java.util.stream.Collectors;

public class CollectingAndThenExample3 {
    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
            new Person("Alice", 30),
            new Person("Bob", 25),
            new Person("Charlie", 35),
            new Person("David", 30),
            new Person("Emily", 28)
        );

        // 将流中的对象收集到一个列表后,过滤出年龄大于30的人
        List<Person> filteredPeople = people.stream()
            .collect(Collectors.collectingAndThen(Collectors.toList(), list -> {
                return list.stream()
                    .filter(p -> p.getAge() > 30)
                    .collect(Collectors.toList());
            }));
        System.out.println("Filtered People: " + filteredPeople);
    }
}

    Logo

    GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。

    更多推荐