使用 Comparator 的 ConcurrentSkipListSet 不会添加新的唯一值
ConcurrentSkipListSet using Comparator will not add new unique values
我想要一组按长度最长 -> 最短排序的并发字符串值。
这是我的代码 (JAVA 8):
private ConcurrentSkipListSet<String> sortedSourceTypeNames = new ConcurrentSkipListSet<>(Comparator.comparing(String::length).reversed());
这是 java 8 文档:
/**
* Constructs a new, empty set that orders its elements according to
* the specified comparator.
*
* @param comparator the comparator that will be used to order this set.
* If {@code null}, the {@linkplain Comparable natural
* ordering} of the elements will be used.
*/
public ConcurrentSkipListSet(Comparator<? super E> comparator) {
m = new ConcurrentSkipListMap<E,Object>(comparator);
}
奇怪的是:
- 添加新值"some_str" -> 确定
- 添加新值"some_els" -> 未添加
- 添加新值"some" -> 确定
调试此现象我看到 ConcurrentSkipListSet 正在拒绝新的唯一字符串,这些字符串的长度与集合中已存在的字符串的长度相同。
我就像 Waaaattt?!?!?
这是任何文档中都未提及的意外行为。
这是 JAVA ConcurrentSkipListSet 实现中的错误吗?还是我做的?
编辑:
感谢大家的快速回复!
我只想指出此行为记录在 JAVA SortedSet 接口中(但不在 ConcurrentSkipListSet 中):
* <p>Note that the ordering maintained by a sorted set (whether or not an
* explicit comparator is provided) must be <i>consistent with equals</i> if
* the sorted set is to correctly implement the <tt>Set</tt> interface. (See
* the <tt>Comparable</tt> interface or <tt>Comparator</tt> interface for a
* precise definition of <i>consistent with equals</i>.) This is so because
* the <tt>Set</tt> interface is defined in terms of the <tt>equals</tt>
* operation, but a sorted set performs all element comparisons using its
* <tt>compareTo</tt> (or <tt>compare</tt>) method, so two elements that are
* deemed equal by this method are, from the standpoint of the sorted set,
* equal. The behavior of a sorted set <i>is</i> well-defined even if its
* ordering is inconsistent with equals; it just fails to obey the general
* contract of the <tt>Set</tt> interface.
您提供的比较器 returns 相同长度的字符串相等,因此忽略重复项。
默认使用ConcurrentSkipListSet
就像
Set<String> set = new ConcurrentSkipListSet<>(
Comparator.comparing(s -> s));
或
Set<String> set = new ConcurrentSkipListSet<>(
Comparator.naturalOrder());
当您设置比较器时,您替换了默认比较器,如果您的比较器声明两个对象相等,它不会默认返回默认行为。
解决此问题的一种方法是先按长度排序,然后再按相等长度的内容排序。
Set<String> set = new ConcurrentSkipListSet<>(
Comparator.comparing(String::length).reversed()
.thenComparing(s -> s));
set.add("aa");
set.add("bb");
set.add("aaa");
set.add("ccc");
System.out.println(set);
打印
[aaa, ccc, aa, bb]
我想要一组按长度最长 -> 最短排序的并发字符串值。
这是我的代码 (JAVA 8):
private ConcurrentSkipListSet<String> sortedSourceTypeNames = new ConcurrentSkipListSet<>(Comparator.comparing(String::length).reversed());
这是 java 8 文档:
/**
* Constructs a new, empty set that orders its elements according to
* the specified comparator.
*
* @param comparator the comparator that will be used to order this set.
* If {@code null}, the {@linkplain Comparable natural
* ordering} of the elements will be used.
*/
public ConcurrentSkipListSet(Comparator<? super E> comparator) {
m = new ConcurrentSkipListMap<E,Object>(comparator);
}
奇怪的是:
- 添加新值"some_str" -> 确定
- 添加新值"some_els" -> 未添加
- 添加新值"some" -> 确定
调试此现象我看到 ConcurrentSkipListSet 正在拒绝新的唯一字符串,这些字符串的长度与集合中已存在的字符串的长度相同。
我就像 Waaaattt?!?!?
这是任何文档中都未提及的意外行为。
这是 JAVA ConcurrentSkipListSet 实现中的错误吗?还是我做的?
编辑:
感谢大家的快速回复!
我只想指出此行为记录在 JAVA SortedSet 接口中(但不在 ConcurrentSkipListSet 中):
* <p>Note that the ordering maintained by a sorted set (whether or not an
* explicit comparator is provided) must be <i>consistent with equals</i> if
* the sorted set is to correctly implement the <tt>Set</tt> interface. (See
* the <tt>Comparable</tt> interface or <tt>Comparator</tt> interface for a
* precise definition of <i>consistent with equals</i>.) This is so because
* the <tt>Set</tt> interface is defined in terms of the <tt>equals</tt>
* operation, but a sorted set performs all element comparisons using its
* <tt>compareTo</tt> (or <tt>compare</tt>) method, so two elements that are
* deemed equal by this method are, from the standpoint of the sorted set,
* equal. The behavior of a sorted set <i>is</i> well-defined even if its
* ordering is inconsistent with equals; it just fails to obey the general
* contract of the <tt>Set</tt> interface.
您提供的比较器 returns 相同长度的字符串相等,因此忽略重复项。
默认使用ConcurrentSkipListSet
就像
Set<String> set = new ConcurrentSkipListSet<>(
Comparator.comparing(s -> s));
或
Set<String> set = new ConcurrentSkipListSet<>(
Comparator.naturalOrder());
当您设置比较器时,您替换了默认比较器,如果您的比较器声明两个对象相等,它不会默认返回默认行为。
解决此问题的一种方法是先按长度排序,然后再按相等长度的内容排序。
Set<String> set = new ConcurrentSkipListSet<>(
Comparator.comparing(String::length).reversed()
.thenComparing(s -> s));
set.add("aa");
set.add("bb");
set.add("aaa");
set.add("ccc");
System.out.println(set);
打印
[aaa, ccc, aa, bb]