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

相关推荐
古法老登瞎折腾1 天前
大数据智能运维实战(十一):运维 MCP 的工程化——权限、限流、审计与错误处理
java·大数据·运维·spring ai·mcp
学逆向的1 天前
C 堆区内存管理
c语言·开发语言·网络安全
huoyueyi1 天前
《融天AI-APP从0到1开发实录》
开发语言·lua
智能运维指南1 天前
研制过程“两张皮“怎么破:研制一体化支撑平台的定位、能力边界与落地前提
java·前端·人工智能·嘉为蓝鲸
yz_aiks1 天前
Spring AI 2.1 ChatMemory 已过时用什么替代:迁移到 Session Memory 实战(JDBC 存储与会话压缩)
java·spring boot·大模型·ai agent·spring ai
金銀銅鐵1 天前
[Java] 用 GUI 展示 EnumMap 增删键值对时的内部变化
java·后端·ai编程
学长毕设1 天前
基于SpringBoot的上门洗车服务系统设计与实现
java·spring boot·后端
jason成都1 天前
RTKLIB-Java 多基线联合RTK:FIX率从0%到91.5%的三层根因修复
java·gnss·rtklib·rtklib_java
OpenAnolis小助手1 天前
PHP 两个严重漏洞曝光,龙蜥社区 24 小时完成 3 版本修复
开发语言·操作系统·php·龙蜥社区
鱼宵1 天前
Stream 终端操作一次讲透:collect、count、reduce 怎么选
java·stream·终端操作