#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>>
, или он может даже быть перегружен для поддержки обоих вариантов.