Объединение значений карты в Java 8 с потоками

У меня есть два Maps, которые должны иметь одни и те же ключи (предположение).

Мне нужно выполнить действие над соответствующими элементами

Код Java 7:

Map<X,Y> m1, m2;

for (Map.Entry<X,Y> kvp: m1.entrySet()) {
    K key = kvp.getKey();
    Y value1 = kvp.getValue();
    Y value2 = m2.get(key);    


    doSomething(value1, value2);
}

Моя цель-использовать лямбду для такой операции

Что-то вроде

Map<X,Y> m1, m2;

[initStreamHere](m1, m2).forEachCorrespondingEntry((k, v1, v2)-> doSomething(v1, v2));

В общем, это может быть круто, если v1или v2равно null или нет в зависимости от наличия или отсутствия соответствующего ключа.

Предоставляет ли Java такую классную функцию? Или возможно реализовать пользовательский код менее чем в 50 строках?

Моя цель-использовать лямбда-выражение, которое принимает ключ и два соответствующих значения

3 ответа

  1. Что-то вроде этого ?

    m1.entrySet()
      .stream()
      .filter(kvp -> m2.containsKey(kvp.getKey()))
      .forEach(kvp -> doSomething(kvp.getValue(), m2.get(kvp.getKey())));
    
  2. Здесь я написал хороший пример того, как вы можете использовать функцию слияния для ваших целей

    public class MapCombine {
    
    public static Map<String,Integer> combineMaps(Map<String,Integer>map1,Map<String,Integer>map2){
        map2.forEach((key,value)->{
            map1.merge( key, map1.get(key), MapCombine::combine);   
        });
        return map1;
    }
    
    public static int combine(Integer a , Integer b) {
        return a+b;
    }
    
    public static void main (String ...args) {
        Map<String,Integer>map1 = new HashMap<>();
        Map<String,Integer>map2 = new HashMap<>();
        map1.put("Red", 1);
        map1.put("Blue", 12);
        map1.put("Black", 11);
        map2.put("Red", 1);
        map2.put("Blue", 111);      
    
        // This will print total for each color
        System.out.println(combineMaps(map1, map2));
    
    }
    

    }

    Вот выход {красный = 2, синий=24, черный=11}

  3. Пока это только любопытный вопрос. Для производства / ваших коллег лучше написать что-то более понятное.

    interface EntryConsumer<K, V> {
        void apply(K key, V v1, V v2);
    }
    
    public static <K, V> void fancyStreams(Map<K, V> m1, Map<K, V> m2, EntryConsumer<K, V> consumer) {
        Stream
            .concat(m1.entrySet().stream(), m2.entrySet().stream())
            .filter(e -> e.getValue() != null) // filter out nulls
            .collect(Collectors.groupingBy(Map.Entry::getKey))
            .entrySet()
            .stream()
            .filter(e -> e.getValue().size() == 2) // filter out non-matching key-values
            .forEach(e -> consumer.apply(e.getKey(), e.getValue().get(0).getValue(), e.getValue().get(1).getValue()));
    }
    
    public static <K, V> void plainOldIteration(Map<K, V> m1, Map<K, V> m2, EntryConsumer<K, V> consumer) {
        m1.entrySet()
            .forEach(e -> {
                if (m2.containsKey(e.getKey())) 
                    consumer.apply(e.getKey(), e.getValue(), m2.get(e.getKey()))
            });
    }
    
    // Actual usage
    Map<String, Integer> m1, m2;
    m1 = Maps.of("1", 22, "2", 23);
    m2 = Maps.of("1", 20, "2", 19, "3", 21);
    fancyStreams(m1, m2, (k, v1, v2) -> System.out.println(k + ": " + (v1 + v2)));
    plainOldIteration(m1, m2, (k, v1, v2) -> System.out.println(k + ": " + (v1 + v2)));
    

    И ваш фактический запрос (немного подробнее)

    public class EntryStream<K, V> {
    
        private final Map<K, V> m1;
        private final Map<K, V> m2;
    
        private EntryStream(Map<K, V> m1, Map<K, V> m2) {
            this.m1 = m1;
            this.m2 = m2;
        }
    
        public static <K, V> EntryStream<K, V> of(Map<K, V> m1, Map<K, V> m2) {
            return new EntryStream<>(m1, m2);
        }
    
        public void forEachCorrespondingEntry(EntryConsumer<K, V> consumer) {
            m1.entrySet()
                .forEach(e -> {
                    if (m2.containsKey(e.getKey())) consumer.apply(e.getKey(), e.getValue(), m2.get(e.getKey()));
                });
        }
    }
    
    // Usage
    EntryStream.of(m1, m2).forEachCorrespondingEntry((k, v1, v2) -> System.out.println(k + ": " + (v1 + v2)));