Java List去掉重复对象以及保证添加顺序

本文详细介绍了在Java中如何对List对象进行去重操作,包括基本类型和对象类型的去重方法,利用Set、Stream API以及根据对象属性去重的多种策略,并提供了具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JAVA中List对象去除重复值,大致分为两种情况,一种是List、List这类,直接根据List中的值进行去重,另一种是List这种,List中存的是javabean对象,需要根据List中对象的某个值或某几个值进行比较去重。

一、去重

1、List、List对象去重复值

利用Set集合的特性:

   Set<String> set = new LinkedHashSet<>();
   set.addAll(list);
   list.clear();
   list.addAll(set);

通过JDK1.8新特性stream的distinct方法,可以直接处理:

List<String> list = list.stream().distinct().collect(Collectors.toList());

2、List<Student>中对象去重复值

这种的话,不能直接比较List中的对象,需要重写bean对象的equals和hashCode方法,然后通过进行去重,具体例子如下:

public class Student
   private Long id;
   private String name;
 

重写Student对象的equals()方法和hashCode()方法:

	@Override
	public boolean equals(Object o) {
	    if (this == o) return true;
	    if (o == null || getClass() != o.getClass()) return false;
	    Student Student = (Student) o;
	    if (!id.equals(Student.id)) return false;
	    return name.equals(Student.name);
	}
	@Override
	public int hashCode() {
	    int result = id.hashCode();
	    result = 19 * result + name.hashCode();
	    return result;
	}
 
 
	List<Student> students = Arrays.asList(s1, s2, s3);
	List<Student> studentsNew = new ArrayList<>();
	// 去重
	students.stream().forEach(
	       s -> {
	           if (!studentsNew.contains(s)) {
	               studentsNew.add(s);
	           }
	       }
	   );
	 
	List的contains()方法实际上是用对象的equals方法去比较

3、根据对象的属性去重

java8的stream流能完美解对象集合去重问题:

        List<UserCar> list1 = new ArrayList();
        UserCar userCar = new UserCar();
        userCar.setId(1);
        userCar.setCarNo("AA");
        list1.add(userCar);

        UserCar userCar1 = new UserCar();
        userCar1.setId(2);
        userCar1.setCarNo("AA");
        list1.add(userCar1);


        Person p1 = new Person(1, "11");
        Person p2 = new Person(1, "22");
        Person p3 = new Person(2, "11");
        List<Person> persons = Arrays.asList(p1, p2, p3);

1、不使用java8


 private List<UserCar> removeDupliByRecordId(List<UserCar> userCars) {
     Set<UserCar> personSet = new TreeSet<UserCar>((o1, o2) ->                                                        o1.getRecordId().compareTo(o2.getRecordId()));
     personSet.addAll(userCars);

     return new ArrayList<UserCar>(personSet);
 }
    

这也是大多数人第一想到的,借助 TreeSet 去重,其中 TreeSet 的其中一个构造函数接收一个排序的算法,同时这也会用到 TreeSet 的去重策略上。


public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));
}

2、第一种java8写法


List<Person> unique = persons.stream().collect(
      Collectors.collectingAndThen(
              Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Person::getName))), ArrayList::new)
);
unique.forEach(p -> System.out.println(p));

3、第二种java8写法


 List<String> names = new ArrayList<>();//用来临时存储person的id

 List<Person> personList = persons.stream().filter(// 过滤去重
         v -> {
             boolean flag = !names.contains(v.getName());
             names.add(v.getName());
             return flag;
         }
 ).collect(Collectors.toList());

二、保证添加顺序

1、方式一 利用HashSet不能添加重复数据的特性 由于HashSet不能保证添加顺序,所以只能作为判断条件:

private static void removeDuplicate(List<String> list) {
    HashSet<String> set = new HashSet<String>(list.size());
    List<String> result = new ArrayList<String>(list.size());
    for (String str : list) {
        if (set.add(str)) {
            result.add(str);
        }
    }
    list.clear();
    list.addAll(result);
}

2、方式二 利用LinkedHashSet不能添加重复数据并能保证添加顺序的特性 :

private static void removeDuplicate(List<String> list) {
    LinkedHashSet<String> set = new LinkedHashSet<String>(list.size());
    set.addAll(list);
    list.clear();
    list.addAll(set);
}

3、方式三 利用List的contains方法循环遍历:

private static void removeDuplicate(List<String> list) {
    List<String> result = new ArrayList<String>(list.size());
    for (String str : list) {
        if (!result.contains(str)) {
            result.add(str);
        }
    }
    list.clear();
    list.addAll(result);
}

参考文献:
1、https://www.cnblogs.com/pcheng/p/10930944.html 20200525
2、https://blog.csdn.net/tangerr/article/details/90349986 20200525
3、https://blog.csdn.net/lin252552/article/details/81128296 20200525
4、https://blog.csdn.net/xingxiupaioxue/article/details/83786320 20200525

<think>好的,我现在需要解决用户的问题:如何在Java中从List<Entity>中移除重复对象。首先,用户提到的Entity应该是一个自定义类,所以重复对象的定义可能涉及对象的某些属性,而不是内存地址。我需要考虑不同的方法来实现,并确保这些方法适用于用户的情况。 首先,我想到可以通过Java 8的Stream API来处理。使用Stream的distinct()方法,但这个方法默认使用对象的equals()和hashCode()来判断重复。所以如果Entity类没有正确写这两个方法,distinct()可能无法正确。因此,用户可能需要先确保Entity类正确实现了equals和hashCode,或者改用其他方式,比如使用Collectors.toCollection结合TreeSet,通过自定义比较器来。 另一种方法是利用HashSet,因为集合不允许重复元素。但是同样,HashSet的重复判断依赖于equals和hashCode。如果用户不想修改Entity类,可能需要使用TreeSet并提供一个Comparator来定义哪些属性相同即为重复。例如,根据id和name属性来比较。 还有可能用户需要保持列表的顺序,这时候可以使用LinkedHashSet来维护插入顺序,同时重复项。这种方法也需要正确实现equals和hashCode,或者提供Comparator。 另外,可能需要遍历列表,手动检查重复项。比如使用一个临时的HashSet来保存已见过的元素,然后逐个检查,将未重复添加到新列表中。这种方法更灵活,可以在遍历时根据特定字段判断重复,不需要修改Entity类。 还需要考虑性能问题,特别是当列表很大时。使用Stream API或HashSet的方法通常时间复杂度是O(n),而手动遍历如果实现不当可能会达到O(n²),但合理使用HashSet的话还是线性的。 此外,用户提到的引用中有关于Java 8 lambda表达式操作List的内容,比如分组、排序等,这可能提示用户希望使用Java 8的特性来实现。因此,Stream API的方法会更符合用户的预期。 可能的陷阱包括:未正确实现equals/hashCode导致失败,或者使用了错误的比较器导致逻辑错误。此外,并行流处理时需要注意线程安全问题,但在这个场景中可能不适用。 总结可能的解决方案: 1. 使用Stream的distinct()方法,要求Entity正确写equals和hashCode。 2. 使用Stream配合TreeSet和自定义Comparator,根据特定字段。 3. 使用LinkedHashSet保持顺序,需要正确实现equals/hashCode或使用Comparator。 4. 遍历列表,手动检查重复项,使用HashSet辅助。 接下来需要验证这些方法的具体实现步骤,并确保示例代码正确。例如,对于方法2,可以使用Stream的collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Entity::getId)))),但要注意TreeSet会根据比较器,所以需要确保比较器覆盖所有必要字段。 另外,用户的问题中引用了CSDN的博客,里面提到使用lambda表达式进行分组、排序等操作,所以可能涉及根据多个字段的情况,这时候需要构造复合键,比如使用多个属性的组合作为比较条件。 最后,需要将这些方法以清晰的步骤呈现给用户,并提供示例代码,同时指出注意事项,比如保持顺序、性能考虑、是否需要修改Entity类等。</think>在Java中从`List<Entity>`中移除重复对象,可通过以下方法实现: --- ### 方法1:使用Java 8 Stream API的`distinct()` **适用条件**:`Entity`类已正确写`equals()`和`hashCode()`方法,通过属性定义对象唯一性。 ```java List<Entity> uniqueList = list.stream() .distinct() .collect(Collectors.toList()); ``` --- ### 方法2:自定义比较器(无需写`equals/hashCode`) **适用场景**:根据特定字段(如`id`和`name`)判断重复。 ```java List<Entity> uniqueList = list.stream() .collect(Collectors.toCollection( () -> new TreeSet<>(Comparator.comparing(Entity::getId) .thenComparing(Entity::getName))) ) .stream().collect(Collectors.toList()); ``` --- ### 方法3:利用`LinkedHashSet`保持顺序 **适用场景**:需要保留原列表顺序且基于属性。 ```java Set<Entity> seen = new LinkedHashSet<>(); for (Entity entity : list) { if (seen.add(entity)) { // 依赖equals/hashCode // 若未写,需手动判断:!seen.stream().anyMatch(e -> e.getId().equals(entity.getId())) } } List<Entity> uniqueList = new ArrayList<>(seen); ``` --- ### 方法4:手动遍历过滤 **适用场景**:灵活控制逻辑,无需修改`Entity`类。 ```java Set<Object> uniqueKeys = new HashSet<>(); List<Entity> uniqueList = list.stream() .filter(entity -> { String key = entity.getId() + "|" + entity.getName(); return uniqueKeys.add(key); // 若key不存在则保留 }) .collect(Collectors.toList()); ``` --- ### 注意事项 1. **性能**:使用`HashSet`或`Stream`的时间复杂度为$O(n)$,手动遍历可能为$O(n^2)$。 2. **字段选择**:若根据多个字段,需构造复合键(如拼接字符串或自定义对象)[^1]。 3. **对象修改**:若`Entity`是可变对象,修改属性可能导致`HashSet`行为异常。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值