如何比较两组对象不使用比较器和流覆盖 equals/hashCode

How to compare two Sets of objects Not overriding equals/hashCode with Comparator and Streams

我有两个 Set,如下所示:

Set<Book> s1 = createBooks();
Set<Book> s2 = createBooks(); // or any set of values

和这个方法:

private Set<Book> createBooks() {

    List<String> name = Arrays.asList("book 1", "book 2", "book 3");
    List<BookType> type = Arrays.asList(BookType.TYPEONE, BookType.TYPETWO);

    Set<Book> listOfBooks = new HashSet<>();

    for(int i=0; i<2; i++) {
        Book book = new Book();
        book.setName(name.get(i));
        book.setType(type.get(i));
        listOfBooks.add(books);
    }

    return listOfBooks;
}

还有这个class:

Class Book {

 private String name;
 private BookType type;

 //here is getter and setter ...

 }

我确实实现了这个 Comparator,但我不确定它是否正常工作:

   Comparator<Book> comparingBooks = (o1, o2) -> {
        if (o1.getName().compareTo(o2.getName()) == 0) {
            return o1.getType().compareTo(o2.getType());
        }
        return o1.getName().compareTo(o2.getName());
    };


     //I did try this implementation but am not sure it's working as well:

     //Comparator<Book> comparingBooks = Comparator.comparing((Book b)->b.getNName())
              .thenComparing(b->b.getType());

期望结果为true时的集合示例:

s1 = (new Book("book 1", BookType.ONE), new Book("book 2", BookType.TWO));
s2 = (new Book("book 1", BookType.ONE), new Book("book 2", BookType.TWO));

期望结果为false时的集合示例:

s1 = (new Book("book 1", BookType.ONE), new Book("book 2", BookType.TWO));     
s2 = (new Book("book 1", BookType.ONE), new Book("book 2", BookType.ONE));

我需要将这些集合与以下内容进行比较:

// this flag should validate any difference of Name 
// and Type by returning true, 
// if both Sets have exactly the same objects, 
// it should return false.
boolean compareBooks = s1.stream().anyMatch(a -> s2.stream().anyMatch(b -> comparingBooks.compare(a, b) != 0));

我也试过了,但没有用,而且总是 return 相同的值:

    boolean compareBooks = SetUtils.isEqualSet(s1, s2);

我没有 equals 和 hashcode 实现,因此无法实现。

有没有其他方法可以用 java 8 和比较器来检查和比较这些集合?

您可以使用比较器创建一个 TreeSet 来实现相等而不是 equals():

Set<Books> listOfBooks = new TreeSet<>(comparingBooks);

现在您可以使用标准的收集方法来比较集合:

boolean compareBooks = !Collections.disjoint(s1, s2);

比较器修复

为了在这种情况下创建 Comparator,您需要显式提供通用类型信息,例如:<Book, String>comparing(),其中 BookStringComparator.comparing() 期望作为参数的 Function 的参数类型和 return 类型。

如果没有显式声明,编译器没有足够的数据来确定变量 book 的类型,在 comparing()thenComparing() 中,其类型将被推断为 Object.

Comparator<Book> comparingBooks = 
      Comparator.<Book, String>comparing(book -> book.getName())
                           .thenComparing(book -> book.getType());

如果只使用了一个静态方法,book变量的类型将是编译器根据语言环境变量的 类型正确推断为 Book Comparator<Book> comparingBooks.

两种方法 lambda 表达式都可以替换为方法引用:

Comparator<Book> comparingBooks =
      Comparator.<Book, String>comparing(Book::getName)
                          .thenComparing(Book::getType);

for information on the syntax of generic methods, take a look at this tutorial

for more information on how to build comparators with Java 8 methods take a look at this tutorial

should validate any difference of Name and Type by returning true, if both Sets have exactly the same objects, it should return false.

Stream s1.stream().anyMatch(a -> s2.stream().anyMatch(b -> ...)) 当前正在检查第一组 s1 中是否有一个元素与 s2 中的 ANY 元素不同。 IE。对于在 s1 中遇到的第一个没有匹配元素的元素,嵌套的 anyMatch() 将 return trues2。经过Book("book 1", BookType.ONE)(s1)与Book("book 2", BookType.TWO)(s2 ) anyMatch() 由 returning true 终止。并包含 anyMatch() 操作传播此结果。

与第二个例子完全一样。 相同的一对元素不同,虽然你改变了类型,名称不相等。结果是 true.

注:

  • 按照惯例 类 通常用 单数名词 命名,即 Book(不是 Books) , Event, Person, 等等
  • 根据经验,如果您的对象打算与集合一起使用,则它们必须实现 equals/hashCode 契约,您的要求非常不寻常。