Подтвердить что ты не робот

Java map.get(key) - автоматически делать put (ключ) и возвращать, если ключ не существует?

Меня тошнит от следующего шаблона:

value = map.get(key);
if (value == null) {
    value = new Object();
    map.put(key, value);
}

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

Я уверен, что что-то существует, чтобы избежать этого, но мои усилия в Googling ничего не дали. Любые предложения?

4b9b3361

Ответ 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?