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);
}
source to share
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.
source to share