在 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 以下可用 | 代码冗长 |
最佳实践建议
-
推荐使用 Stream API:代码简洁,可读性好
-
考虑使用 LinkedHashSet:如果需要保持顺序
-
总是处理 null 值:避免 NullPointerException
-
大数据量考虑并行流:但要注意线程安全问题
-
使用具体类型:明确指定 Set 的实现类型,便于维护