如何为现有Java 8流添加单个Key值?

时间:2019-06-27 18:27:40

标签: java java-8 java-stream collectors

这是我要填充静态地图的工作

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}

是否可以在Collectors.toMap()中加入明确的看跌期权?

4 个答案:

答案 0 :(得分:3)

如果您愿意使用第三方库,则可以使用Eclipse CollectionsImmutableMap创建一个静态Stream内联。

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;
    }
}

您还可以通过使用本机Eclipse Collections API稍微简化代码。

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

注意:我是Eclipse Collections的提交者

答案 1 :(得分:1)

我实际上认为不需要为此使用Java Streams。您只需使用static块来初始化其中的mapEnumput附加值:

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));

或者,如果您还想将所有名称添加到枚举值本身,则可以这样更改类:

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::newCollectors.toMap()

答案 2 :(得分:1)

您可以使用Collectors::collectAndThen修改结果图

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

下面的方法是枚举

static Map<String, FooBar> addCustom(Map<String, FooBarEnum> map) {
    map.put("xx", FooBar.A);
    return map;
}

答案 3 :(得分:0)

您不能直接将其传递给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-中看到所有可用的替代。

但是,在使用Stream.concat调用toMap之前,您可以确保流具有构造地图所需的所有对。您可以从枚举中合并配对,以及要添加的手动配对。

我的独立代码必须定义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}