返回

Java 8 Stream API 过滤集合:按唯一属性过滤

java

使用 Java 8 Stream API 按属性过滤集合

在 Java 8 中,我们可以使用 Stream API 对集合进行强大的操作,包括过滤。当需要根据对象属性的独特性对集合进行过滤时,可以使用 Collector.groupingBy() 方法。

问题:按属性过滤集合

假设我们有一个 Person 对象列表,每个对象都有一个名称属性。我们希望过滤列表,仅保留每个名称唯一的 Person 对象。默认情况下,distinct() 方法使用对象的默认相等性检查,这可能不是我们想要的。

解决方案:Collector.groupingBy()

为了解决这个问题,我们可以使用 Collector.groupingBy() 方法。它按指定的属性对集合中的元素进行分组,然后我们可以选择每个组中的第一个元素。

List<Person> distinctPersons = persons.stream()
        .collect(Collectors.groupingBy(Person::getName))
        .values()
        .stream()
        .map(List::get)
        .toList();

代码示例

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class DistinctByProperty {

    public static void main(String[] args) {
        // 创建一个 Person 对象列表
        List<Person> persons = Arrays.asList(
                new Person("John", "Doe"),
                new Person("Jane", "Doe"),
                new Person("John", "Smith"),
                new Person("Jane", "Smith")
        );

        // 使用 Collector.groupingBy() 按名称分组
        List<Person> distinctPersons = persons.stream()
                .collect(Collectors.groupingBy(Person::getName))
                .values()
                .stream()
                .map(List::get)
                .toList();

        // 打印不包含重复名称的 Person 集合
        System.out.println(distinctPersons);
    }

    private static class Person {
        private String firstName;
        private String lastName;

        public Person(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }

        public String getName() {
            return firstName + " " + lastName;
        }

        @Override
        public String toString() {
            return firstName + " " + lastName;
        }
    }
}

结论

使用 Collector.groupingBy() 方法,我们可以有效地按对象属性过滤集合,从而仅保留具有唯一属性值的元素。这种技术对于清理数据、查找重复项以及执行其他基于属性的过滤操作非常有用。

常见问题解答

  • 为什么 distinct() 方法不直接提供按属性过滤的重载?
    • distinct() 方法用于检查对象是否相等,默认情况下使用对象的默认相等性检查。为了按属性进行过滤,需要使用更灵活的 Collector.groupingBy() 方法。
  • 是否还有其他方法可以按属性过滤集合?
    • 可以使用流的 filter() 方法,结合 lambda 表达式来检查属性的唯一性。然而,这种方法可能比 Collector.groupingBy() 效率较低,尤其是在集合非常大的情况下。
  • 可以使用 Collector.groupingBy() 对其他数据结构进行分组吗?
    • Collector.groupingBy() 不仅可以用于集合,还可以用于其他数据结构,例如 Map 和 Set。这使其成为一个通用且强大的分组工具。
  • Collector.groupingBy() 的时间复杂度是多少?
    • Collector.groupingBy() 的时间复杂度为 O(n),其中 n 是集合中的元素数量。
  • 如何处理具有多个唯一属性的对象?
    • 对于具有多个唯一属性的对象,可以使用 Collectors.toMap() 方法,它允许指定一个键提取器和一个值提取器。这将创建键为唯一属性值,值为对象的映射。