Java map.get(key) - автоматически делать put (ключ) и возвращать, если ключ не существует?
Меня тошнит от следующего шаблона:
value = map.get(key);
if (value == null) {
value = new Object();
map.put(key, value);
}
Этот пример только царапает поверхность дополнительного кода, который должен быть записан, когда у вас есть вложенные карты для представления многомерной структуры.
Я уверен, что что-то существует, чтобы избежать этого, но мои усилия в Googling ничего не дали. Любые предложения?
Ответы
Ответ 1
java.util.concurrent.ConcurrentMap
и из Java 8
Java.util.Map
имеет
putIfAbsent(K key, V value)
который возвращает значение, отображаемое на ключ, или вставляет заданное значение и null, если для ключа не отображается значение.
Если вам нужна ленивая оценка значения,
computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)
Ответ 2
Java 8 добавляет хороший метод Map: compute, computeIfPresent, computeIfAbsent
Чтобы выполнить то, что вам нужно:
Object existingOrCreated = map.computeIfAbsent(key, (k) -> new Object());
Ответ 3
Проблема с этим шаблоном заключается в том, что вам нужно каким-то образом определить значение, которое должно использоваться, если get()
возвращает null.
Там, конечно, есть библиотеки, и у IIRC есть еще несколько новых коллекций, которые делают это, но, к сожалению, я не помню, какие из них были.
Однако вы можете сами написать метод утилиты, если у вас есть стандартный способ создания новых значений. Возможно, что-то подобное:
public static <K, V> V safeGet(K key, Map<K,V> map, Class<V> valueClass) throws /*add exceptions*/ {
V value = map.get(key);
if( value == null ) {
value = valueClass.newInstance();
map.put( key, value );
}
return value;
}
Обратите внимание, что вам придется либо выбросить исключения отражения, либо обработать их в методе. Кроме того, для этого требуется valueClass
предоставить конструктор без аргументов. Кроме того, вы можете просто передать значение по умолчанию, которое должно использоваться.
Ответ 4
Вы можете использовать MutableMap и getIfAbsentPut()
из Коллекции Eclipse, который возвращает значение, сопоставленное с ключом, или вставляет заданное значение и возвращает заданное значение, если значение не отображается на ключ.
Вы можете использовать ссылку метода для создания нового Object
:
MutableMap<String, Object> map = Maps.mutable.empty();
Object value = map.getIfAbsentPut("key", Object::new);
Или вы можете напрямую создать новый Object
:
MutableMap<String, Object> map = Maps.mutable.empty();
Object value = map.getIfAbsentPut("key", new Object());
В первом примере объект будет создан только в том случае, если на ключ не будет введено значение.
Во втором примере объект будет создан независимо.
Примечание. Я участвую в коллекциях Eclipse.
Ответ 5
РЕДАКТИРОВАТЬ: Обратите внимание: функция, упомянутая ниже, устарела, и вместо нее следует использовать CacheBuilder.
Библиотека Guava имеет " вычислительную карту", см. MapMaker.makeComputingMap(Function).
Map<String, Object> map = new MapMaker().makeComputingMap(
new Function<String, Object>() {
public String apply(Stringt) {
return new Object();
}
});
Если вам нужна функция несколько раз, извлеките ее в класс утилиты, а затем создайте Map как это (где MyFunctions.NEW_OBJECT
- статический экземпляр функции):
Map<String, Object> map = new MapMaker()
.makeComputingMap(MyFunctions.NEW_OBJECT);
Ответ 6
Если в любом случае вам нужно получить данные по умолчанию на карте, если они не существуют
map.getOrDefault(key, defaultValue);
javadocs
Ответ 7
Возможно, я не вижу всей проблемы, но как насчет использования наследования или композиции для добавления этого поведения к объекту Map?