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 的实现类型,便于维护

相关推荐
SEO_juper10 小时前
外贸多语言站最隐蔽的流量杀手:hreflang 错了,谷歌把德语页推给美国人(附审计脚本)
开发语言·前端·python·seo·独立站·谷歌优化
無a伟10 小时前
RabbitMq高级特性:TTL,死信队列,延迟队列
java·分布式·rabbitmq
geovindu10 小时前
CSharp: Strategy Pattern
开发语言·后端·c#·.net·.netcore·策略模式·行为模式
长谷深风11110 小时前
Agent 跑了 30 分钟宕机,如何从断点继续?
java·大数据·人工智能·ai·大模型·memory·aiagent
慧都小妮子10 小时前
DevExpress Java 文档处理 API 免费 CTP:PDF、PowerPoint、条码与跨平台部署
java·pdf·powerpoint·devexpress·文档处理·条码生成
泡海椒10 小时前
告别反射低效:JQuick-Java ASM动态调用链性能优化实战
java·python·性能优化
Tairitsu_H10 小时前
[C++] C++11新增构造:列表初始化和std::initializer_list
开发语言·c++·c++11·构造
土司大王10 小时前
LeetCode 17 电话号码的字母组合:Java 回溯模板、多叉决策树与复杂度分析
java·leetcode·决策树
宣宣猪的小花园.11 小时前
【嵌入式】故障与降级:看门狗、保护机制和工程可靠性的底线
开发语言·人工智能·嵌入式硬件·机器学习
shmily麻瓜小菜鸡11 小时前
JS/TS 易踩坑知识点 — 自动分号插入(ASI)
开发语言·javascript·ecmascript