Проблема: в документации для contains и add для ConcurrentSkipListSet (csls) указано следующее:
public boolean add (E e) Добавляет указанный элемент к этому набору, если он еще не присутствует. Более формально добавляет заданный элемент e к этому набору, если в наборе нет элемента e2 такого, что e.equals(e2). Если этот набор уже содержит элемент, вызов оставляет его неизменным и возвращает false.
public boolean contains (Object o) Возвращает true, если этот набор содержит указанный элемент. Более формально возвращает true тогда и только тогда, когда этот набор содержит элемент e такой, что o.equals(e).
Но я не вижу такого поведения. Приведенный ниже код (единичный тест) раскрывает несоответствие.
@Test
public void testComparison() throws Exception {
ObjectKey key = new ObjectKey("a", "b")
MetricTimeDataContext entry1 = new MetricTimeDataContext(1l, "Count", 10, 0, key)
MetricTimeDataContext entry2 = new MetricTimeDataContext(1l, "Count", 10, null, key)
Assert.assertEquals(1, entry1 <=> entry2) // the compare shows entry1 > entry2
Assert.assertNotEquals(entry1, entry2) // entry != entry2
Assert.assertEquals(Boolean.FALSE, entry2.equals(entry1)) // EDIT: Added this since documentation states it is performing this test. this passes..
Assert.assertNotEquals(entry1.hashCode(), entry2.hashCode()) // hashcodes are diff
// this block shows correct functionality of ConcurrentHashMap
def final Map<MetricTimeDataContext, Boolean> store = new ConcurrentHashMap<>()
store.put(entry1, Boolean.TRUE)
Assert.assertFalse(store.containsKey(entry2)) // correct! since entry1 != entry2
store.put(entry2, Boolean.TRUE)
Assert.assertEquals(2, store.size()) // correct! 2 items added.
// this block shows INcorrect functionality of ConcurrentSkipListSet
def final Set<MetricTimeDataContext> dataStore = new ConcurrentSkipListSet<>()
Assert.assertTrue(dataStore.add(entry1))
Assert.assertFalse(dataStore.contains(entry2)) // <--- this line fails unit test. why ???
Assert.assertTrue(dataStore.add(entry2)) // <-- this line also fails if above line is absent
}
Мне что-то не хватает? Вышеуказанные записи (entry1, entry2) явно не равны, но все же я не могу добавить их как csls. что дает?
Мне нужно использовать параллельную структуру данных, так как этот код будет использоваться в распределенном env (akka). Также MetricTimeDataContext реализует сравнимые, как показано в приведенном выше модульном тесте, и имеет соответствующие значения equals и hashcode.
Благодарю.
UPDATE: [SOLVED] Итак, благодаря подталкиванию @mbs и @JasonC я добавил еще 2 теста на самом верху:
Assert.assertEquals(Boolean.FALSE, entry2.equals(entry1))//это проходит (равенство в порядке) Assert.assertEquals(-1, entry2 <=> entry1)//это возвращает 0 вместо -1 (comp сломан)
Поэтому мой алгоритм сравнения неверен. ,
Еще раз спасибо.
Ява:
java version "1.7.0_21"
Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)
Groovy:
[INFO] \- org.codehaus.groovy:groovy-all:jar:2.1.5:compile
Платформа:
Linux ariel 3.5.0-43-generic #66~precise1-Ubuntu SMP Thu Oct 24 14:52:23 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
Скорее всего, ваши равноценны (поскольку ConcurrentHashMap в порядке), но compareTo не соответствует (поскольку проблема ConcurrentSkipListMap является проблемой). Я бы проверил в вашем тесте, что compareTo и equals соответствуют объектам, которые вы используете.
Я добавил это обновление в свое первоначальное сообщение после нескольких минут после публикации, так как SO не позволяет вам отвечать на собственный вопрос в течение 8 часов.
Поэтому я добавил еще 2 теста на самом верху:
Assert.assertEquals(-1, entry2 <=> entry1) // this returns 0 instead of -1
Assert.assertEquals(Boolean.FALSE, entry2.equals(entry1))
Поэтому мой алгоритм сравнения был неправильным. @JasonC поразил это примерно через 15 минут после того, как я разместил это.
Кроме того, документация вводит в заблуждение, поскольку в ней четко указано, что добавление зависит от того, на что она равна. Добавление зависит от compareTo и в моем случае entry2.compareTo(entry1), который возвращал 0 вместо -1.
Разумеется, лучше всего иметь равные с вашей логикой compareTo.
Так спасибо всем, кто ответил.