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

标签 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. 添加新值“some_str” -> 确定
  2. 添加新值“some_els” -> 未添加
  3. 添加新值“some” -> 确定

调试此现象时,我发现 ConcurrentSkipListSet 拒绝与集合中现有字符串具有相同长度的新的唯一字符串。

我就像 Waaaattt?!?!?

这是一种意外行为,任何文档中均未提及。

这是 JAVA ConcurrentSkipListSet 实现中的错误吗?还是我做了什么?

编辑:

感谢大家的快速回复!

我只是想指出,这种行为记录在 JAVA SortedSet 接口(interface)中(但没有记录在 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.

最佳答案

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

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 - 使用 Comparator 的 ConcurrentSkipListSet 不会添加新的唯一值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48101005/

相关文章:

java - 如何在 Slick2D 中对字体大小进行动画处理,而无需每次渲染创建新的字体实例?

java - 如何使用 java 8 将二维对象集/ArrayList 转换为一个平面集/列表

java - 将 java.time.temporal.Temporal 转换为 java.util.Date

java - Lambda vs 匿名内部类性能 : reducing the load on the ClassLoader?

Java 多线程 - 使用 Fork-Join 方法在列表中查找最大元素

java - 如何确保 java 中并发列表的元素(在列表循环后添加)得到正确处理?

java - 限制 Hibernate Criteria 查询中关联的类

java - Java-8 中 Stream 的循环融合(内部工作原理)

java - 从 Excel 文件读取空单元格时出现异常

java - 类条件的等待方法不抛出 InterruptedException