Java TreeMap содержит ключ, но вызов containsKey возвращает false (даже ключ является точно таким же неизмененным объектом)

Почему возможно зациклить keySet TreeMap и получить .containsKey == false?

for (Object thisObject : map.keySet()) {
    if (!map.containsKey(thisObject)) {
        System.out.println("This line should be never reached.");
    }
}

После большого количества различных итераций и вызовов эта строка попадает в цель. map.get(thisObject) вернет null. Но отладка показывает, что ключ (та же ссылка, значение и хэш) и фактическое значение находятся на карте. Карта небольшая (25 элементов) TreeMap<Long, Double>

ОБНОВЛЕНИЕ:

Как предположил @rgettman, при построении TreeMap используется пользовательская сортировка Comparator (не видел ее, потому что она была построенный из другого класса). Этот компаратор был просто (я думаю) скопирован из здесь

Изменение Comparator:

  public int compare(Object a, Object b) {

    if((Double)base.get(a) > (Double)base.get(b)) {
      return 1;
    } else if((Double)base.get(a) == (Double)base.get(b)) {
      return 0;
    } else {
      return -1;
    }
  }

to

...
    } else if(base.get(a).equals(base.get(b))) {
      return 0;
...

устраняет проблему. Причина, по которой эта проблема появлялась сразу после миллионов операций, заключалась в том, что не было случаев, когда карта имела два одинаковых значения для двух разных ключей, так как это очень маловероятно в данном контексте.

So at:

25151l, 1.7583805400614032
24827l, 1.7583805400614032

это терпит неудачу.

Спасибо за помощь!


person 309963d8521805330a44bdcb3d87f3    schedule 07.08.2013    source источник
comment
вы можете попробовать изменить == на .equals?   -  person Ramesh Kotha    schedule 07.08.2013
comment
@RameshK Я имею в виду, что ОП уже подтвердил, что это тот же реф, так что не должно быть проблем с ==, не так ли?   -  person Dennis Meng    schedule 07.08.2013
comment
Какое ключевое значение терпит неудачу?   -  person rgettman    schedule 07.08.2013
comment
Значение ключа 24827.   -  person 309963d8521805330a44bdcb3d87f3    schedule 07.08.2013
comment
В качестве проверки вменяемости; это в однопоточном приложении?   -  person Dennis Meng    schedule 07.08.2013
comment
Поскольку он небольшой, не могли бы вы добавить SSCCE со всеми ключами и значениями, чтобы мы могли его запустить?   -  person c.s.    schedule 07.08.2013
comment
Не могли бы вы попробовать использовать Long thisObject : map.keySet()?   -  person Joop Eggen    schedule 07.08.2013
comment
Вам обязательно нужно показать содержимое карты, чтобы сделать это ответственным.   -  person arshajii    schedule 07.08.2013
comment
Один из способов заставить это потерпеть неудачу — предоставить Comparator конструктору TreeMap, который нарушает контракт Comparator, т. е. не возвращает 0 для равных значений.   -  person rgettman    schedule 07.08.2013


Ответы (3)


Вы, должно быть, внесли изменения в бэкинг entrySet()/Map.Entry, тем самым изменив ключевые порядки, тем самым получив неудачный поиск containsKey.

person Joop Eggen    schedule 07.08.2013

Я только что выполнил код, этот случай вернул мне true.

          TreeMap<Long,Double> otm = new TreeMap<Long, Double>();
          otm.put(1L, 1.0);
          otm.put(2L, 2.0);

        for (Object thisObject : otm.keySet()) {
                System.out.println(otm.containsKey(thisObject));
        }     

Не могли бы вы предоставить нам данные, которые вы вводите в TreeMap. Спасибо

Это реализация containsKey(Object key) из JavaDocs.

содержитКлюч

boolean содержитKey(ключ объекта)

Возвращает true, если эта карта содержит сопоставление для указанного ключа.

Более формально, возвращает true тогда и только тогда, когда эта карта содержит отображение для ключа k такого, что (key==null ? k==null : key.equals(k)). (Таких отображений может быть не больше одного.)

Параметры:

key - key whose presence in this map is to be tested Returns:
true if this map contains a mapping for the specified key Throws:
ClassCastException - if the key is of an inappropriate type for this map (optional)
NullPointerException - if the specified key is null and this map does not permit null keys (optional

Надеюсь, это поможет.

person JNL    schedule 07.08.2013
comment
Что, если проблема заключается в конкретной паре, добавленной OP, которой нет в вашем примере? Дело в том, что OP знает, что он должен вернуть true, но хочет знать, почему его конкретный случай не соответствует действительности. Попытка какого-то другого случайного случая вообще не отвечает на вопрос. - person Dennis Meng; 07.08.2013
comment
@DennisMeng Мне любопытно узнать о такой конкретной паре. Моя точка зрения заключалась в том, что ОП, возможно, не реализовал это правильно. Вот почему я хотел увидеть конкретный случай. Вы сталкивались с такими случаями? Если да, я был бы признателен, если бы вы могли сообщить мне о том же. - person JNL; 07.08.2013
comment
Я думаю, но есть разница между уверен, что вы не сделали x ошибку, и я попробовал этот другой случай, и это сработало для меня нормально - person Dennis Meng; 07.08.2013
comment
Конечно, но это происходит после того, как миллионы вызовов возвращают здесь false. Постараюсь предоставить SSCCE ... - person 309963d8521805330a44bdcb3d87f3; 07.08.2013
comment
Это было бы круто. Потому что, если в отладчике хэш-код такой же, мне тоже любопытно узнать о том же. - person JNL; 07.08.2013

Большинство этих классов реализации полагаются на поддержку и правильность как hashCode(), так и equals().

Если у вас действительно одинаковый хэш-код от объектов, попробуйте сопоставить равенство. Предложенный мной ответ состоит в том, что они не совпадают.

В противном случае сценарий должен быть достаточно небольшим, чтобы вы могли опубликовать объекты и/или их соответствующий хэш-код и метод equals.

person Niels Bech Nielsen    schedule 08.08.2013
comment
Хэш-код Long основан на его значении public int hashCode() { return (int)(value ^ (value >>> 32)); }. - person 309963d8521805330a44bdcb3d87f3; 08.08.2013