使用Comparator的ConcurrentSkipListSet不会添加新的唯一值

时间:2018-01-04 17:58:56

标签: java java-8 java.util.concurrent

我想要一组并行的字符串值,按长度排序最长 - >最短的。

这是我的代码(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);
    }

现在这是有线的事情:

  1. 添加新值&#34; some_str&#34; - &GT;确定
  2. 添加新值&#34; some_els&#34; - &GT; 未添加
  3. 添加新值&#34;一些&#34; - &GT;确定
  4. 调试这种现象我看到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.
    

1 个答案:

答案 0 :(得分:3)

你有提供者的比较器返回相同长度的字符串相等,因此重复被忽略。

默认使用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]