У меня есть Map<String, List<String>>
в моем коде, где я бы избегал потенциальных нулевых указателей, если метод map #get()
возвращал пустой список вместо null. В java API есть что-то подобное? Должен ли я просто расширить HashMap
?
Реализация Java Map, которая возвращает значение по умолчанию вместо null
Ответ 1
@Ответ на вопрос - это хороший способ сделать то, что вы задаете напрямую.
Но мне кажется, что то, что вы пытаетесь реализовать, - это "multimap"; то есть отображение от ключа к набору значений. Если это так, то вы также должны посмотреть на классы мультимапов в коллекциях коллекций Guava или Apache.
Посмотрите:
-
com.google.common.collect.Multimap
интерфейс и его реализация, или -
org.apache.commons.collections.MultiMap
интерфейс и его реализации. -
org.apache.commons.collections4.MultiMap
интерфейс и его реализации (новая версия предыдущей MultiMap, введенная в v4).
Ответ 2
Как отмечено в комментариях:
Концепция компьютерной карты Guava была заменена на
LoadingCache
. Также java 8 представил интерфейс карты nicecomputeIfAbsent
метод по умолчанию, который не нарушает договор карты и не дает ленивой оценки.
Guava имел идею "вычислительной карты", которая будет выполнять функцию, чтобы обеспечить значение, если оно не присутствует. Он был реализован в MapMaker.makeComputingMap
; теперь вы можете использовать CacheBuilder
- подробнее CacheBuilder.build
.
Это может быть излишним для того, что вам нужно - вам может быть лучше просто написать реализацию Map
, которая имеет 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
}
Ответ 3
Благодаря методам 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"
Ответ 4
Как и в предыдущих сообщениях, вы можете просто переопределить метод 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;
}
};
Ответ 5
В Guava есть способ сделать именно то, что вы хотите. Это похоже на Арготе ответ.
Map<String, List<String>> myMap = ...
Functions.forMap(myMap, Arrays.asList("default", "value"));
Ответ 6
Мне кажется, что вы можете просто написать функцию-оболочку, чтобы получить нужное значение, и если она null
возвращает значение по умолчанию.
Map<String, List<String>> myMap = new Map<String, List<String>>();
public List<String> myGet(String key) {
List<String> ret = myMap.get(key);
if(ret == NULL) {
return defaultList(); // where defaultList is a function that generates your default list.
}
return ret;
}
Это предполагает, что ваш myMap
является глобальной переменной (для простоты), если это не то, что вы хотите, вы также можете расширить Map
или HashMap
во что-то вроде myMap
и просто включить эту дополнительную функцию, Таким образом, вы можете использовать его из любого места, где создается объект myMap
.