Ошибка "несоответствие нулевых ограничений" при реализации Map.entrySet (Java8, Eclipse)

Я получаю ошибку...

The return type is incompatible with 'Set<Map.Entry<K,T>>' returned from Map<K,T>.entrySet() (mismatching null constraints)

... при реализации Map и переопределение Map.entrySet как это:

package org.abego.util;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
...    
public abstract class MyMap<K, T> implements Map<K, T> {
    private Map<K, T> map = new LinkedHashMap<>();

    @Override
    public Set<java.util.Map.Entry<K, T>> entrySet() {
        return map.entrySet();
    }
    ...
}

Посылка org.abego.util определяет недействительность по умолчанию, чтобы быть @NonNull:

@org.eclipse.jdt.annotation.NonNullByDefault
package org.abego.util;

Единственный способ избавиться от ошибки - "удалить аннотацию по умолчанию" для entrySet используя @NonNullByDefault({}) аннотация:

package org.abego.util;
...
import org.eclipse.jdt.annotation.NonNullByDefault;

public abstract class MyMap<K, T> implements Map<K, T> {
    ...
    @Override
    @NonNullByDefault({})
    public Set<java.util.Map.Entry<K, T>> entrySet() {
        return map.entrySet();
    }
    ...
}

Хотя это работает, мне интересно, если это правильный способ исправить ошибку.

(Я использую Eclipse 4.5 (Mars) и jdk1.8.0_60.)

1 ответ

Решение

Вы пытаетесь переопределить этот метод:

Set<Map.Entry<K, V>> entrySet();

с методом, чья эффективная подпись

@NonNull Set<@NonNull Map.Entry<K, V>> entrySet();

Это несовместимое переопределение, которое можно продемонстрировать с помощью этого вызывающего абонента:

Set<Map.Entry<Foo,Bar>> entries = someMap.entrySet();
entries.add(null);

Если someMap имеет тип MyMap тогда тип элемента entries является @NonNull, но контракт java.util.Map.entrySet() обещает Set где null элементы допускаются (множество не указало недействительность своих элементов). Смешивание обоих контрактов (с @NonNull и не указано) на том же объекте entries сломает клиентов, которые принимают ненулевые элементы.

Глядя на Javadoc entrySet()однако следует с уверенностью предположить, что Map.entrySet() всегда будет возвращать Set с ненулевыми элементами. Следовательно, корень проблемы заключается в том, что java.util.Map.entrySet() не имеет нулевых аннотаций

Начиная с "Затмения Марса", это можно преодолеть с помощью внешних нулевых аннотаций. Вы можете сказать компилятору, что тип возвращаемого значения Map.entrySet() на самом деле @NonNull Set<@NonNull Map.Entry<K,V>>либо применяя команду Annotate в IDE, либо помещая следующий фрагмент в файл java/util/Map.eea внутри каталога, который был настроен как место для внешних аннотаций для JRE:

class java/util/Map

entrySet
 ()Ljava/util/Set<Ljava/util/Map$Entry<TK;TV;>;>;
 ()L1java/util/Set<L1java/util/Map$Entry<TK;TV;>;>;

С такими внешними аннотациями ваша программа будет принята нулевым анализом JDT.

Другие вопросы по тегам