繁体   English   中英

如何比较两组对象不使用 Comparator 和 Streams 覆盖 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));

我也试过这个但是没有用并且总是返回相同的值:

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

我没有 equals 和 hashcode 实现,也无法实现它。

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

比较器的修复

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

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

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

如果仅使用 static 方法之一,编译器将根据语言环境变量Comparator<Book> comparingBooks类型book变量的类型正确推断为Book

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

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

有关泛型方法语法的信息,请查看本教程

有关如何使用 Java 8 种方法构建比较器的更多信息,请查看本教程

Stream

应通过返回 true 来验证 Name 和 Type 的任何差异,如果两个 Set 具有完全相同的对象,则应返回 false。

Stream s1.stream().anyMatch(a -> s2.stream().anyMatch(b ->...))当前正在检查第一个集合s1中是否有一个元素不同于 s2 中的任何元素. 即嵌套的anyMatch()将为在s1中遇到的第一个元素返回true ,而在s2中没有匹配的元素。 在将Book("book 1", BookType.ONE) ( s1 ) 与Book("book 2", BookType.TWO) ( s2 ) 进行比较后, anyMatch()通过返回true终止。 并附anyMatch()操作传播这个结果。

第二个例子也会发生同样的情况。 同一对元素不同,虽然你换了一个类型,名字却不一样 结果是true

笔记:

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM