如果java集合包含两个相同的元素,如何返回false

如果java集合包含两个相同的元素,如何返回false,java,java-stream,Java,Java Stream,我有一个收藏。事件看起来像这样 public class Event { private Integer id; private LocalDateTime localDateTime; // getters, setters omitted } 该集合中的每个事件都需要具有唯一的id和localDateTime。如果条件满足,如何使用流API进行检查并返回true import java.util.concurrent.atomic.AtomicInteger;

我有一个收藏。事件看起来像这样

public class Event {

   private Integer id;
   private LocalDateTime localDateTime;

   // getters, setters omitted
}

该集合中的每个事件都需要具有唯一的id和localDateTime。如果条件满足,如何使用流API进行检查并返回true

 import java.util.concurrent.atomic.AtomicInteger;
    public class Event {

       private static final AtomicInteger idGenerator = new AtomicInteger(1000);
       private Integer id;
       private LocalDateTime localDateTime;

       public Event(){
          id = idGenerator.getAndIncrement();
       }
       // getters, setters omitted
}
代码测试

public class Test {
    public static void main(String[] args) {
        for(int i = 0; i < 10; ++ i){
            System.out.println(new Event().getId());
        }
    }
}

首先,重写方法equals和hashcode并按如下方式编写:

@Override
public boolean equals(Object o){
if (o instanceof Event){
    Event e = (Event) o;
    return e.id.equals(this.id) && e.localDateTime.equals(this.localDateTime);
}
else return false;
}

@Override
public int hashCode(){
return Objects.hash(id,localDateTime); //this is the default implementation, up to you to implement it in a better way
}
然后,您可以像这样使用流来检查是否存在任何重复项:

public boolean checkAllUnique(Collection<Event> col){
    return col.stream().allMatch(new HashSet<>()::add);
}
您可以使用两个HashSet作为备份集合来存储唯一元素,并在事件列表上迭代,如下所示:

public boolean duplicateExists(List<Event> eventList) {
    Set<Integer> ids = new HashSet<>();
    Set<LocalDateTime> localDateTimes = new HashSet<>();
    return eventList.stream()
            .anyMatch(event -> !ids.add(event.getId()) ||
                    !localDateTimes.add(event.getLocalDateTime()));
}
这是您需要的事件类

class Event {

    private Integer id;

    private LocalDateTime localDateTime;

    public Integer getId() {
        return id;
    }

    public LocalDateTime getLocalDateTime() {
        return localDateTime;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setLocalDateTime(LocalDateTime localDateTime) {
        this.localDateTime = localDateTime;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Event event = (Event) o;
        return id.equals(event.id) &&
                localDateTime.equals(event.localDateTime);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, localDateTime);
    }

    public static boolean hasDuplicates(List<Event> events) {
        /*
            return events
            .stream()
            .noneMatch(e -> events
                    .stream()
                    .filter(ev -> ev.equals(e)).count() > 1);
         */
         return events.stream()
             .distinct()
             .count() != events.size(); // Kudos to @Holger for this approach.
    }
}

这是一个静态函数,因此不会对对象创建产生任何影响。不过,您可以将其用作检查重复项的实用方法。您只需要一行检查。

equals和hashCode是如何实现的?它们是否仅依赖于这两个属性?^^具有唯一的id和localDateTime。。。它们中的每一个或两者的组合的唯一值?查找一个iterable是否有两个相等的元素与在log n上对其排序具有相同的复杂性。因此,您要么保留一个helper HashSet来检查成员身份,同时对其进行迭代以达到分摊的复杂性,要么对其进行排序并通过将每个元素压缩到下一个元素来进行迭代并检查是否相等。@每个元素的值都是唯一的。@downvoter能否请您详细说明为什么我的问题没有用处?非常感谢您的帮助花点时间看片段。我不太熟悉这种方法。现在,我想我已经对它的工作原理有了一些了解。我想,您可能会因为.equals和.hashCode的实现而感到困惑。请参阅此以了解一些不了解的->。大多数Java核心实现都基于这两种方法。如果您已经覆盖了这两个方法,那么覆盖这两个函数都是必需的,因此equals-hashcode契约,您只需在对象上调用event1.equalsevent2即可。这就是为什么containes函数在这里也起作用。这段代码毫无意义。您正在对列表中的项目进行流式处理,以检查这些项目是否都不包含在该列表中,这是一个矛盾。hasDuplicates返回true的唯一时间是在给定一个空列表的情况下。在列表上进行流式处理,再在列表上对每个元素进行流式处理,将导致糟糕的性能,也称为二次时间复杂度。为什么不使用return events.stream.distinct.count!=事件。大小@霍尔格,哇,这是一个很好的方法。因为Integer和LocalDateTime永远不会冲突,所以这里不需要两个哈希集,一个哈希集就可以了。但是我会用循环而不是流。你是对的,我忘记了演员阵容,现在就纠正它
class Event {

    private Integer id;

    private LocalDateTime localDateTime;

    public Integer getId() {
        return id;
    }

    public LocalDateTime getLocalDateTime() {
        return localDateTime;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setLocalDateTime(LocalDateTime localDateTime) {
        this.localDateTime = localDateTime;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Event event = (Event) o;
        return id.equals(event.id) &&
                localDateTime.equals(event.localDateTime);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, localDateTime);
    }

    public static boolean hasDuplicates(List<Event> events) {
        /*
            return events
            .stream()
            .noneMatch(e -> events
                    .stream()
                    .filter(ev -> ev.equals(e)).count() > 1);
         */
         return events.stream()
             .distinct()
             .count() != events.size(); // Kudos to @Holger for this approach.
    }
}