Как сопоставить поток с неизменяемым Java-классом? - PullRequest
0 голосов
/ 22 ноября 2018

Рассмотрим фрагмент кода:

imnport reactor.util.context.Context

public Context addAll (Context ctx, Map.Entry<String, Object> hashMap) {
    Context ctxVar = ctx;
    for (Map.Entry<String, Object> e : hashMap.entrySet()) {
        if (e.getValue() != null) {
            ctxVar = ctxVar.put(e.getKey(), e.getValue());
        }
    }
    return ctxVar;
}

reactor.util.context.Context является неизменным классом.Таким образом, put объединяет старый контекст с новым добавленным значением и возвращает новый контекст.

Вопрос в том, существует ли более компактный способ "объединить" HashMap в неизменяемый объект с использованием потоков Java 8?(Не только для класса Context)

Примечание: я читал о сборке потока Java, и кажется, что это не работает, потому что я должен предоставить начальный Context и объединить несколько контекстов после сопоставления, но воссоздать весь контекст для объединенияоперации, я думаю, это слишком много.

Ответы [ 2 ]

0 голосов
/ 23 ноября 2018

Ваш вопрос меня заинтересовал.Я исследовал эту тему.

Вот что я придумал:

package reactor.util.context;

import java.util.Map;
import java.util.Map.Entry;
import static java.util.stream.Collectors.toMap;

public class ContextUtils {
    public static Context putAll(Context context, Map map) {
        if (map.isEmpty()) {
            return context;
        } else {
            Map contextMap = context.stream()
                                    .filter(e -> e.getValue() != null)
                                    .collect(toMap(Entry::getKey, Entry::getValue));
            return new ContextN(contextMap, map);
        }
    }
}

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

Это решение может выглядеть неоптимально, поскольку оно создает новые HashMap с initiaCapacity = 0 и loadFactor = 0.75f ​​.На самом деле, это не проблема, поскольку ContextN сам является подклассом HashMap с точной емкостью и loadFactor = 1 .Данные из промежуточной карты будут скопированы в контекст и позже будут собраны GC.

Примечание : служебный класс должен находиться в пакете reactor.util.context.ContextN означает package-private, поэтому он недоступен из других пакетов.

0 голосов
/ 22 ноября 2018

Вы можете использовать reduce:

Context ctxVar = hashMap.entrySet()
                        .stream()
                        .filter(e -> e.getValue() != null)
                        .reduce(ctx,
                                (c, e) -> c.put(e.getKey(), e.getValue()),
                                (c1, c2) -> c1.putAll(c2));

Хотя это кажется расточительным (точно так же, как ваш исходный цикл расточительным), поскольку создает несколько Context экземпляров, когда только последний

Это имеет больше смысла, если вы напишите static метод Context класса (или конструктор), который принимает Map и создает только один экземпляр Context длязаписи Map.Однако теперь я заметил, что вы не написали этот класс Context, поэтому вы не можете его изменить.

...