Java 8 ConcurrentHashMap initialization

I'm looking for a "CLEAN and Simple" method to initialize a ConcurrentHashMap.

As of Java 8, I have this: -

private static final Map<String, String> myStreamedMap = Stream.of(
        new AbstractMap.SimpleImmutableEntry<>("Key1", "Value1"), 
        new AbstractMap.SimpleImmutableEntry<>("Key2", "Value2"), 
        new AbstractMap.SimpleImmutableEntry<>("Key3", "Value3"), 
        new AbstractMap.SimpleImmutableEntry<>("Key4", "Value4")).
        collect(Collectors.toMap((entry) -> entry.getKey(), (entry) -> entry.getValue()));

      

Which gives the desired end result, however I feel

" new AbstractMap.SimpleImmutableEntry<>

"

It's hard to understand what's going on.

Is there any way to "hide" this and stick to one line?

UPDATE

Came up with this (obvious) solution

private static final Map<String, String> myStreamedMapWith = Stream.of(
        with("Key1", "Value1"), 
        with("Key2", "Value2"), 
        with("Key3", "Value3"), 
        with("Key4", "Value4")).
        collect(Collectors.toMap((entry) -> entry.getKey(), (entry) -> entry.getValue()));

private static AbstractMap.SimpleImmutableEntry<String, String> with(final String key, final String value) {
    return new AbstractMap.SimpleImmutableEntry<>(key, value);
}

      

+3


source to share


1 answer


Until Java 9 is released, there is no convenient built-in method to initialize the map, so I would recommend looking at a third party library (like Google Guava):

new ConcurrentHashMap<>(com.google.common.collect.ImmutableMap.of("Key1", "Value1"));

      

The main problem anyway is that you are instantiating HashMap

.

from sources Collectors.toMap

:

return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);

      


If you don't want to use any external libraries, a good way is to use the Builder pattern . Here's a simple example:

class MapBuilder<K, V> {

    private List<Map.Entry<K, V>> entries = new ArrayList<>();

    public MapBuilder<K, V> with(K key, V value) {
        entries.add(new AbstractMap.SimpleImmutableEntry<>(key, value));

        return this;
    }

    public Map<K, V> build(Supplier<Map<K, V>> mapSupplier) {
        return entries.stream().collect(Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue,
                (k1, k2) -> k1,
                mapSupplier
                )
        );
    }

}

      



And his demo:

new MapBuilder().with("Key1", "Value1")
                .with("Key2", "Value2")
                .build(ConcurrentHashMap::new);

      


To be completely implementation-independent ( AbstractMap.SimpleImmutableEntry

), I suggest introducing a constructor that takes an input initializer BiFunction<KEY, VALUE, Map.Entry<KEY, VALUE>>

as an argument:

class MapBuilder<K, V> {

    private List<Map.Entry<K, V>> entries;
    private BiFunction<K, V, Map.Entry<K, V>> function;

    public MapBuilder() {
        entries = new ArrayList<>();
    }

    public MapBuilder(BiFunction<K, V, Map.Entry<K, V>> function) {
        this();
        this.function = function;
    }

    public MapBuilder<K, V> with(K key, V value) {
        entries.add(function.apply(key, value));

        return this;
    }

    public Map<K, V> build(Supplier<Map<K, V>> mapSupplier) { ... }

}

      

The call will be changed to:

new MapBuilder<>(AbstractMap.SimpleImmutableEntry::new);

      

At this point, we can decide which implementation should be chosen both for the record and for the card separately.

+5


source







All Articles