Java中Set和SortedSet接口之间的逻辑不一致
我注意到Java中的Set和SortedSet接口之间存在逻辑不一致。
如果在比较期间它们相同,则SortedSet将不同的对象(通过equal()方法)识别为equals,但它在逻辑上是不正确的。 对象的比较应仅对对象的顺序负责。
例如:我可以有很多产品,我想按价格对它们进行排序。 在这种情况下,SortedSet不能包含具有相同价格的不同产品:[“salt”,0.5 $],[“milk”,1 $],[“bread”,1 $],[“bananas”,2 $ ]在上面的例子中,牛奶将被面包取代。 在这种情况下,将违反inheritance的Set接口的合同,因为不相等的对象会相互替换。 我更新了SortedSet的JavaDoc并且知道这个行为有很好的记录,但我认为这是一个逻辑上的失败。
你有什么看法,也许你已经和Set和SortedSet有类似的问题了?
这不是一个逻辑上的失败,而是一个设计属性。 请注意,如果您的比较算法与equals一致,则a.compareTo(b) == 0
将等效于a.equals(b)
。
javadoc实际上非常明确:
即使排序与equals不一致,排序集的行为也是明确定义的; 它只是不遵守Set接口的一般合同。
这有用吗?
这实际上为您希望达到特定行为提供了灵活性。 比方说,例如,您希望将字符串放入SortedSet并将它们排序,忽略大小写,您可以使用:
Set set = new TreeSet<> (String.CASE_INSENSITIVE_ORDER);
这将达到预期的效果,但是:
set.add("ABC"); set.add("abc");
只会在您的集合中添加一个字符串,因为它们将被视为与该特定比较器相等。
您可能意味着在Object
实际可用的equals()
方法,因此Java中的每个对象类型都会覆盖它或从Object
inheritance它。
在Java中,一般来说,如果a.equals(b) == true
,则两个对象a
和b
是相同的。 而Set,每个Set,甚至SortedSet都没有重复,所以如果你重写equals
来比较price属性,那么如果它们具有相同的价格,则两个对象是相同的。
我猜你不会覆盖equals
方法,但提供一个Comparator
到SortedSet
来进行排序。 在这种情况下,如另一个答案所述,如果a.compareTo(b) == 0
将等于a.equals(b)
。
如果您想订购该Set,您需要的是另一个结构,例如List来进行排序。 就像是:
List list = new ArrayList (myUnorderedProductsSet); Collections.sort(list, comparatorByPrice);
请注意,这不会复制或复制您的产品Bean,只是将以不同顺序引用相同对象的另一个结构。 所以不是昂贵或可避免的东西。