【问题标题】:Checking the equality of lists of Comparable objects in Groovy在 Groovy 中检查 Comparable 对象列表的相等性
【发布时间】:2017-11-16 15:36:55
【问题描述】:

我正在使用 Spock 框架编写一个测试,在测试列表的相等性时发现了一个奇怪的问题。

当我比较两个列表时

sourceList == targetList

并且这些列表包含相同类型的 Comparable 对象,这些对象使用其 compareTo 方法而不是 equals 进行相等性测试。

在对此类列表进行相等性测试时,是否有任何简单的方法可以强制 Groovy 使用 equals?

这是一个简单的测试规范,其中测试应该失败,但事实并非如此。

class Test extends Specification {

def "list test"() {
    when:
        def listA = [[index: 1, text: "1"] as Bean, [index: 2, text: "2"] as Bean]
        def listB = [[index: 1, text: "1"] as Bean, [index: 2, text: "3"] as Bean]

    then:
        listA == listB
}

class Bean implements Comparable<Bean> {

    int index
    String text

    @Override
    public int compareTo(Bean o) {
        return index.compareTo(o.index);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + index;
        result = prime * result + ((text == null) ? 0 : text.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof Bean)) {
            return false;
        }
        Bean other = (Bean) obj;
        if (index != other.index) {
            return false;
        }
        if (text == null) {
            if (other.text != null) {
                return false;
            }
        } else if (!text.equals(other.text)) {
            return false;
        }
        return true;
    }

}

}

【问题讨论】:

  • 你能提供一个可重现的样本吗?
  • @Rao 查看编辑后的问题
  • 感谢您的编辑,您使用的是 java 还是 groovy?

标签: groovy


【解决方案1】:

要求简单 方法是主观的。这个答案的关键在于,在 Groovy 中,is() 方法将 check object equality

ArrayList 上考虑这种新方法。如果合适,它会将两个列表压缩在一起,并在每对项目上调用is()

ArrayList.metaClass.myCompare = { listB ->
    def result = false
    def listA = delegate
    if (listB && listA.size() == listB.size()) {
        def zipped = [listA, listB].transpose()
        result = zipped.inject(true){ ok, pair ->
            ok && pair[0].is(pair[1])
        }
    }
    result
}

然后:

def beanA = new Bean(index: 1, text: 'a')
def beanA1 = new Bean(index: 1, text: 'a')
def beanB = new Bean(index: 2, text: 'b')

assert [beanA, beanB].myCompare([beanA, beanB])
assert ! [beanA, beanB].myCompare([beanA1, beanB])
assert ! [beanA, beanB].myCompare([beanA])
assert ! [beanA, beanB].myCompare(null)
assert ! [beanA, beanB].myCompare([])

【讨论】:

    【解决方案2】:

    在 groovy 中,如果项目不可比较,“==”将替换为 equals,如果它们实现了 Comparable,则替换为 compareTo。不知道一个简单的强制equals方法,如果集合没有重复,可以逐个检查集合的元素:

    def collectionsEqual (Collection<?> collection1, Collection<?> collection2) {
         if (collection1.size() != collection2.size()) {
             return false
         }
         for (elem1 in collection1) {
             def founded = false;
             for (elem2 in collection2) {
                 if (elem1?.equals (elem2)) {
                     founded = true
                 }
             }
             if (!founded) {
                return false
             }
         }
         true
    }
    

    但是,在https://www.baeldung.com/java-compareto 我们有:

    强烈建议(尽管不是必需的)保留 compareTo 实现与equals方法一致 实现:

    x.compareTo(y) == 0 应该具有与 x.equals(y) 相同的布尔值 这将确保我们可以安全地使用排序集中的对象和 已排序的地图。

    【讨论】:

      猜你喜欢
      • 2014-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-04
      • 2022-08-22
      • 2015-07-19
      • 1970-01-01
      相关资源
      最近更新 更多