Реализация карты Java, которая возвращает значение по умолчанию вместо нуля - PullRequest
36 голосов
/ 29 января 2011

У меня есть Map<String, List<String>> в моем коде, где я бы избегал потенциальных нулевых указателей, если бы метод #get() карты возвратил пустой список вместо нулевого.Есть ли что-нибудь подобное в API Java?Должен ли я просто расширить HashMap?

Ответы [ 6 ]

31 голосов
/ 09 апреля 2014

Благодаря default методам, Java 8 теперь имеет встроенную функцию с Map::getOrDefault:

Map<Integer, String> map = ...
map.put(1, "1");
System.out.println(map.getOrDefault(1, "2")); // "1"
System.out.println(map.getOrDefault(2, "2")); // "2"
25 голосов
/ 29 января 2011

@ Ответ Джона - это хороший способ сделать то, о чем вы спрашиваете напрямую.

Но мне кажется, что то, что вы пытаетесь реализовать, является «мультикартой»;то есть сопоставление ключа с набором значений.Если это так, то вам также следует взглянуть на мультикартовые классы в коллекциях общих ресурсов Guava или Apache.

Посмотрите:

24 голосов
/ 29 января 2011

Как отмечено в комментариях:

Концепция вычислительной карты Гуавы была заменена на LoadingCache. Также в интерфейс Map добавлен Java 8: хороший computeIfAbsent метод по умолчанию, который не нарушает контракт карты и отличается ленивой оценкой.


У Гуавы была идея "вычислительной карты", которая будет выполнять функцию для предоставления значения, если оно отсутствует. Это было реализовано в MapMaker.makeComputingMap; теперь вы можете использовать CacheBuilder - см. CacheBuilder.build для более подробной информации.

Это может быть излишним для того, что вы ищете - вам может быть лучше просто написать реализацию Map, которая имеет a Map (с использованием композиции, а не расширения какой-либо конкретной реализации), а затем просто верните значение по умолчанию, если оно отсутствует. Каждый метод, кроме get, может просто делегировать другую карту:

public class DefaultingMap<K, V> implements Map<K, V>
{
    private final Map<K, V> map;
    private final V defaultValue;

    public DefaultingMap(Map<K, V> map, V defaultValue)
    {
        this.map = map;
        this.defaultValue = defaultValue;
    }

    @Override public V get(Object key)
    {
        V ret = map.get(key);
        if (ret == null)
        {
            ret = defaultValue;
        }
        return ret;
    }

    @Override public int size()
    {
        return map.size();
    }

    // etc
}
10 голосов
/ 29 января 2011

Аналогично предыдущим постам, за исключением того, что вы можете просто переопределить метод get, если хотите изменить его поведение.

Map<String, List<String>> map = new LinkedHashMap<String, List<String>>() {
    public String get(Object key) {
        List<String> list = super.get(key);
        if (list == null && key instanceof String)
           super.put(key, list = new ArrayList<String>());
        return list;
    }
}; 
7 голосов
/ 08 января 2014

У Гуавы есть метод, чтобы делать именно то, что вы хотите. Это похоже на ответ Арго .

Map<String, List<String>> myMap = ...
Functions.forMap(myMap, Arrays.asList("default", "value"));
0 голосов
/ 29 января 2011

Мне кажется, что вы можете просто написать функцию-обертку, чтобы получить желаемое значение, и, если оно null, вместо этого вернуть значение по умолчанию.глобальная переменная (для простоты), если это не то, что вам нужно, вы также можете расширить Map или HashMap на что-то вроде MyMap и просто включить эту дополнительную функцию.Таким образом, вы можете использовать его из любого места, где создается объект MyMap.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...