比较具有多个列表属性的两个对象的最佳方法是什么

时间:2019-07-19 13:37:23

标签: java list comparator comparable

我有一个具有多个列表属性的POJO / DTO类,例如

class Boo {    
    private List<Foo> foos;
    private List<Integer> pointers;
}

我想比较两个列表是否包含相同的值而忽略列表的顺序。是否可以在不打开对象和对列表进行排序的情况下实现这一目标?

我们将不胜感激。在此先感谢

2 个答案:

答案 0 :(得分:1)

“我想比较两个值是否包含相同的值,而不是列表的顺序。”

没有通用相等运算符。有时您想按某些属性比较对象。典型的例子可能是比较字符串,有时“计算机”等于或不等于“计算机”或“Vesterålen”等于或不等于“ Vesteralen”。

Java 中,您可以重新定义对象之间的默认等价关系(修改默认行为!)。

对象List使用所包含对象的默认等价关系作为默认的等价关系,并按顺序检查该相等性。

下面的示例仅忽略一个属性中的元素顺序:

class My {
    private final List<String> xs;
    private final List<Integer> ys;

    My(List<String> xs, List<Integer> ys) {
        this.xs = xs;
        this.ys = ys;
    }

    public List<Integer> getYs() {
        return ys;
    }

    public List<String> getXs() {
        return xs;
    }

    @Override
    public int hashCode() {
        return xs.hashCode() + 7 * ys.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if(!(obj instanceof My))
            return false;
        My o = (My) obj;
        return
                // ignoring order
                getXs().stream().sorted().collect(toList()).equals(o.getXs().stream().sorted().collect(toList()))
                // checking order
                && getYs().equals(o.getYs());
    }
}

public class Callme {
    public static void main(String... args) {
        My m1 = new My(asList("a", "b"), asList(1, 2));
        My m2 = new My(asList("b", "a"), asList(1, 2));
        My m3 = new My(asList("a", "b"), asList(2, 1));
        System.out.println(m1.equals(m2));
        System.out.println(m1.equals(m3));
    }
}

有输出

true
false

但是我无法定义您所需的等价关系,例如,我不会忽略一个列表是否包含比另一个列表更多的元素,但也许您希望(例如,您等于{{1 }}比{a, b, a})。

因此,请为您的对象定义等价关系,并覆盖{b, a}hashCode

答案 1 :(得分:0)

这归结为比较列表。如果项目的顺序无关紧要,则最好使用Set代替List

然后,您的等于

public boolean equals(object other) {
    //here be class and null checks
    return foos.equals(other.foos) && pointers.equals(other.pointers);
}

如果您不能使用Set,则可能是因为您可以多次拥有相同的商品,或者是因为订单很重要,所以您可以通过互惠的containsAll()进行与上述相同的操作。仍然不会考虑重复的条目,但否则可以很好地工作。

您声明不能编辑类Boo。一种解决方案是拥有一个服务类,该类为您执行类似于Objects.equals()的服务。

class BooComparer {

    public static bool equals(Boo a, Boo b) {
        //again do some null checks here
        return a.foos.containsAll(b.foos) 
          && b.foos.containsAll(a.foos)
          && a.pointers.containsAll(b.pointers)
          && b.pointers.containsAll(a.pointers)
    }
}

如果这对您有用-很好。也许您也必须比较其他成员。再说一次:如果其中一个列表有两次输入,这将忽略。