Как добавить одно значение ключа в существующий поток Java 8? - PullRequest
1 голос
/ 27 июня 2019

Вот что я делаю, чтобы заполнить свою статическую карту

public static final Map<String, FooBar> mapEnum = 

Arrays.stream(FooBarEnum.values())
            .collect(Collectors.toMap(e-> StringUtils.upperCase(e.name), e -> e));

Я хочу добавить еще одно значение ключа к этой карте.

mapEnum.put("xx", FooBar.A);

Вот перечисление

public enum FooBar {
   A("a"), B("b"), C("c");
}

Моя статическая карта будет выглядеть после построения карты

{"a":FooBar.A, "b": FooBar.B, "c": FooBar.C, "xx": Foobar.A}

Можно ли включить явный вызов put в Collectors.toMap()?

Ответы [ 4 ]

3 голосов
/ 28 июня 2019

Если вы открыты для использования сторонней библиотеки, вы можете создать статическую ImmutableMap строку с Stream, используя Eclipse Collections .

public static final ImmutableMap<String, FooBar> MAP_ENUM =
        Arrays.stream(FooBar.values())
                .collect(Collectors2.toMap(FooBar::getName, fooBar -> fooBar))
                .withKeyValue("xx", FooBar.A)
                .toImmutable();

public enum FooBar {
    A("a"), B("b"), C("c");

    private String name;

    FooBar(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }
}

Вы также можетенемного упростить код, используя собственные API-интерфейсы Eclipse Collections.

public static final ImmutableMap<String, FooBar> MAP_ENUM =
        ArrayAdapter.adapt(FooBar.values())
                .groupByUniqueKey(FooBar::getName)
                .withKeyValue("xx", FooBar.A)
                .toImmutable();

Примечание. Я являюсь коммиттером для Eclipse Collections

1 голос
/ 27 июня 2019

вы можете использовать Collectors::collectAndThen для изменения приведенной карты

Arrays.stream(FooBarEnum.values())
        .collect(Collectors.collectAndThen(
                    Collectors.toMap(e-> StringUtils.upperCase(e.name), 
                        Function.identity()), FooBarEnum::addCustom));

в enum указан следующий метод

static Map<String, FooBar> addCustom(Map<String, FooBarEnum> map) {
    map.put("xx", FooBar.A);
    return map;
}
1 голос
/ 27 июня 2019

На самом деле я не вижу необходимости использовать Java Streams для этого. Вы можете просто использовать блок static для инициализации mapEnum и put дополнительных значений в нем:

public static final Map<String, FooBar> mapEnum;

static {
    mapEnum = Arrays.stream(FooBar.values())
            .collect(Collectors.toMap(FooBar::getName, Function.identity()));
    mapEnum.put("xx", FooBar.A);
    // ...
}

Collectors.toMap(): Нет никаких гарантий относительно типа, изменчивости, сериализуемости или поточной безопасности возвращаемого {@code Map}.

Чтобы обеспечить изменчивость Map, возвращаемого Collectors.toMap(), чтобы вы могли использовать Map.put(), впоследствии лучше использовать это:

Arrays.stream(FooBar.values())
        .collect(Collectors.toMap(Function.identity(), Function.identity(), (a, b) -> a, HashMap::new));

Если вы действительно хотите использовать потоки Java, вы можете использовать это:

public static final Map<String, FooBar> mapEnum = Stream.concat(
        Stream.of(FooBar.values()).map(e -> Map.entry(e.getName(), e)),
        Stream.of(Map.entry("xx", FooBar.A))
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Или, если вы также хотите добавить все имена в само значение enum, вы можете изменить свой класс следующим образом:

public static enum FooBar {
    A("a", "xx"), B("b"), C("c");

    private String[] names;

    FooBar(String... names) {
        this.names = names;
    }

    public String[] getNames() {
        return names;
    }
}

И используйте это для создания карты:

public static final Map<String, FooBar> mapEnum = Stream.of(FooBar.values())
        .flatMap(e -> Arrays.stream(e.getNames()).map(n -> Map.entry(n, e)))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

До Java 9 использовать new AbstractMap.SimpleEntry<>() вместо Map.entry(). Если вам нужно отсортировать карту, используйте LinkedHashMap::new с Collectors.toMap().

0 голосов
/ 27 июня 2019

Вы не можете напрямую передать его в Collectors.toMap ().Вы можете увидеть все переопределения, доступные в javadocs: https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#toMap-java.util.function.Function-java.util.function.Function-.

Однако вы можете убедиться, что в вашем потоке есть все пары, необходимые для построения карты, прежде чем вызывать toMap с помощью Stream.CONCAT.Вы соединяете пары из enum и пары, которые хотите добавить.

Мой автономный код должен определять класс Pair, но, поскольку вы использовали StringUtils, я думаю, у вас есть библиотека, которая уже включает Pair, поэтомувам не нужно его определять.

Код:

import java.util.*;
import java.util.stream.*;

public class Main {

    private static enum  FooBar {
        A("a"), B("b"), C("c");
        private String name;
        FooBar(String name) {
            this.name = name;
        }
    }

    public static class Pair {
        String a;
        FooBar b;
        Pair(String a, FooBar b) {
            this.a = a;
            this.b = b;
        }
    }

    public static void main(String [] args) {
        System.out.println(
            Stream.concat( 
                Arrays.stream(FooBar.values()).map(e -> new Pair(e.name.toUpperCase(), e)),
                Stream.of(new Pair("xx", FooBar.A))
            )
            .collect(Collectors.toMap(pair -> pair.a, pair -> pair.b))
        );
    }

}

Вывод:

{xx=A, A=A, B=B, C=C}
...