Как вставить одно и то же значение для нескольких ключей хэш-карты с использованием потоков Java

#java #java-8 #hashmap #java-stream

#java #java-8 #хэш-карта #java-stream

Вопрос:

Допустим, у меня есть хэш-карта, и я хочу вставить одно и то же значение в список ключей. Как я могу сделать это с Java 8 без перебора всех ключей и вставки значения? Это скорее вопрос о Java Streams.

Вот простой способ сделать это. Это пример кода, который я написал, чтобы продемонстрировать, чего я хотел достичь.

 public void foo(List<String> keys, Integer value) {
    Map<String, Integer> myMap = new HashMap<>(); 
    for (String key : keys) {
        myMap.put(key, value);
    }
}
  

Есть ли более простой способ выполнить вышеуказанное с использованием Java 8 streams? Как я могу избежать цикла for с использованием потоков Java 8. Спасибо!

[Редактировать-1] Лучший фрагмент кода ниже.

 public void foo() {
    Map<String, Integer> myMap = new HashMap<>(); 
    List<String> keys = getKeysFromAnotherFunction();
    Integer value = getValueToBeInserted(); // Difficult to show my actual use case. Imagine that some value is getting computed which has to be inserted for the keys.
    for (String key : keys) {
        myMap.put(key, value);
    }  

    List<String> keys2 = getNextSetOfKeys();
    Integer newValue = getValueToBeInserted(); 
    for (String key : keys2) {
        myMap.put(key, newValue);
    } 
}
  

Комментарии:

1. myMap Фактически определяется вне foo метода?

2. Да. это верно. Это не фактический код. Это небольшой фрагмент кода, который я быстро придумал, чтобы лучше объяснить, чего я хотел достичь.

3. Вряд ли это может быть проще. Вам нужен цикл. Ярлыка нет.

4. Невозможно сделать это без итерации (если «итерация» не исключает keys.forEach(e -> myMap.put(e, value); )

5. Ваша идея довольно проста. Нет необходимости использовать потоки (они могут повлечь за собой значительные накладные расходы), но вы можете рассмотреть обобщение для метода «foo», чтобы получить список ключей и значение. А также рассмотрите возможность использования myMap.putIfAbsent(), если вы не хотите случайно заменить существующее значение.

Ответ №1:

Используя collector, что-то вроде:

 Map<String, Integer> myMap = keys.stream()
            .collect(Collectors.toMap(key -> key,
                    val -> value, (a, b) -> b));
  

Комментарии:

1. Это не «более простой способ» (заявленное требование) и не использует myMap, который определен вне метода (другое заявленное требование).

2. Спасибо! Я искал что-то вроде этого.

3. @DodgyCodeException Я бы сказал, что «проще» может быть основано на мнении. В любом случае не уверен, что находится myMap вне контекста метода, о котором вы прокомментировали. Переменная myMap кажется локальной для метода в рассматриваемом коде.

Ответ №2:

Я думаю, что ваш вопрос касается выделения некоторого фрагмента кода больше, чем преобразования традиционных for циклов в потоковые конструкции.

Предположим, у вас есть следующий общий метод утилиты:

 public static <K, V, M extends Map<K, V>> M fillMap(
        Supplier<List<K>> keysFactory,
        Supplier<V> singleValueFactory,
        Supplier<M> mapFactory) {

    M map = mapFactory.get();
    List<K> keys = keysFactory.get();
    V singleValue = singleValueFactory.get();

    keys.forEach(k -> map.put(k, singleValue));

    return map;
}
  

Затем вы могли бы использовать приведенный выше метод следующим образом:

 Map<String, Integer> myMap = fillMap(() -> getKeysFromAnotherFunction(),
                                     () -> getValueToBeInserted(),
                                     HashMap::new); // create HashMap

myMap = fillMap(() -> getNextSetOfKeys(),
                () -> getValueToBeInserted(),
                () -> myMap); // use previously created map
  

Существуют варианты приведенного выше кода, т. Е. Метод может получать Map<K, V> экземпляр вместо Supplier<Map<K, V>> , или он может даже быть перегружен для поддержки обоих вариантов.