Java 中将 List 中对象的某一列转换为 Set

在 Java 中将 List 中对象的某一列转换为 Set,有几种常用方法:

1. 使用 Stream API(最常用)

复制代码
import java.util.*;
import java.util.stream.Collectors;

// 示例类
class Person {
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() { return name; }
    public int getAge() { return age; }
}

public class Main {
    public static void main(String[] args) {
        List<Person> personList = Arrays.asList(
            new Person("张三", 25),
            new Person("李四", 30),
            new Person("王五", 25),
            new Person("张三", 28)  // 重复的张三
        );
        
        // 方法1:提取 name 列到 Set(自动去重)
        Set<String> nameSet = personList.stream()
            .map(Person::getName)  // 提取 name
            .collect(Collectors.toSet());
        
        System.out.println(nameSet);  // [张三, 李四, 王五]
        
        // 方法2:提取 age 列到 Set
        Set<Integer> ageSet = personList.stream()
            .map(Person::getAge)
            .collect(Collectors.toSet());
        
        System.out.println(ageSet);  // [25, 30, 28]
    }
}

2. 指定具体的 Set 实现

复制代码
// 使用 HashSet
Set<String> nameSet = personList.stream()
    .map(Person::getName)
    .collect(Collectors.toCollection(HashSet::new));

// 使用 TreeSet(排序)
Set<String> sortedNameSet = personList.stream()
    .map(Person::getName)
    .collect(Collectors.toCollection(TreeSet::new));

// 使用 LinkedHashSet(保持插入顺序)
Set<String> linkedNameSet = personList.stream()
    .map(Person::getName)
    .collect(Collectors.toCollection(LinkedHashSet::new));

3. 处理可能为 null 的情况

复制代码
// 方法1:过滤掉 null
Set<String> nameSet = personList.stream()
    .map(Person::getName)
    .filter(Objects::nonNull)  // 过滤 null
    .collect(Collectors.toSet());

// 方法2:使用 filter 和 Optional
Set<String> nameSet = personList.stream()
    .map(Person::getName)
    .filter(name -> name != null && !name.trim().isEmpty())  // 过滤 null 和空字符串
    .collect(Collectors.toSet());

4. 复杂对象属性提取

复制代码
// 如果属性是嵌套对象
class Department {
    private String deptName;
    // getters and setters
}

class Employee {
    private String name;
    private Department department;
    // getters and setters
}

// 提取嵌套属性
Set<String> deptNames = employeeList.stream()
    .map(Employee::getDepartment)
    .filter(Objects::nonNull)
    .map(Department::getDeptName)
    .collect(Collectors.toSet());

5. 并行流处理(大数据量时)

复制代码
Set<String> nameSet = personList.parallelStream()  // 并行处理
    .map(Person::getName)
    .collect(Collectors.toSet());

6. 传统方法(不使用 Stream)

复制代码
// 传统 for 循环
Set<String> nameSet = new HashSet<>();
for (Person person : personList) {
    nameSet.add(person.getName());
}

// 传统 for 循环,处理 null
Set<String> nameSet = new HashSet<>();
for (Person person : personList) {
    if (person.getName() != null) {
        nameSet.add(person.getName());
    }
}

主要区别对比

方法 优点 缺点
Stream API 代码简洁,可读性好,支持链式调用 Java 8+
并行流 大数据量性能好 线程安全需注意
传统循环 兼容性好,Java 8 以下可用 代码冗长

最佳实践建议

  1. 推荐使用 Stream API:代码简洁,可读性好

  2. 考虑使用 LinkedHashSet:如果需要保持顺序

  3. 总是处理 null 值:避免 NullPointerException

  4. 大数据量考虑并行流:但要注意线程安全问题

  5. 使用具体类型:明确指定 Set 的实现类型,便于维护

相关推荐
毕设源码-郭学长10 小时前
【开题答辩全过程】以 基于SpringBoot技术的美妆销售系统为例,包含答辩的问题和答案
java·spring boot·后端
故事不长丨10 小时前
C#正则表达式完全攻略:从基础到实战的全场景应用指南
开发语言·正则表达式·c#·regex
梨落秋霜10 小时前
Python入门篇【文件处理】
android·java·python
Java 码农11 小时前
RabbitMQ集群部署方案及配置指南03
java·python·rabbitmq
哈库纳玛塔塔11 小时前
放弃 MyBatis,拥抱新一代 Java 数据访问库
java·开发语言·数据库·mybatis·orm·dbvisitor
phltxy11 小时前
从零入门JavaScript:基础语法全解析
开发语言·javascript
S***q37711 小时前
Spring Boot管理用户数据
java·spring boot·后端
天“码”行空12 小时前
java面向对象的三大特性之一多态
java·开发语言·jvm
毕设源码-郭学长12 小时前
【开题答辩全过程】以 基于SpringBoot框架的民俗文化交流与交易平台的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
好大哥呀12 小时前
Java Web的学习路径
java·前端·学习