It seems what you want is just:
ConcurrentMap<String, Model> modelsMap =
models.parallelStream()
.collect(toConcurrentMap(Model::getId, identity()));
This creates a ConcurrentMap
from the list of models by collecting it with Collectors.toConcurrentMap
. The key mapper is the function that returns the name of the model and the value mapper is the identity function.
Note that this will throws an exception is case of duplicate ids.
If you want to create the list of names along with this Map in the same Stream pipeline, you could use the pairing
collector written in this answer and hold the result inside a custom Pair
class. The Map will be the first element of the pair and the list of names will be the second.
Pair<Map<String, Model>, List<String>> pair =
models.parallelStream()
.collect(pairing(
toConcurrentMap(Model::getId, identity()),
mapping(Model::getName, toList()),
Pair::new)
);
static <T, A1, A2, R1, R2, R> Collector<T, ?, R> pairing(Collector<T, A1, R1> c1,
Collector<T, A2, R2> c2, BiFunction<R1, R2, R> finisher) {
EnumSet<Characteristics> c = EnumSet.noneOf(Characteristics.class);
c.addAll(c1.characteristics());
c.retainAll(c2.characteristics());
c.remove(Characteristics.IDENTITY_FINISH);
return Collector.of(() -> new Object[] {c1.supplier().get(), c2.supplier().get()},
(acc, v) -> {
c1.accumulator().accept((A1)acc[0], v);
c2.accumulator().accept((A2)acc[1], v);
},
(acc1, acc2) -> {
acc1[0] = c1.combiner().apply((A1)acc1[0], (A1)acc2[0]);
acc1[1] = c2.combiner().apply((A2)acc1[1], (A2)acc2[1]);
return acc1;
},
acc -> {
R1 r1 = c1.finisher().apply((A1)acc[0]);
R2 r2 = c2.finisher().apply((A2)acc[1]);
return finisher.apply(r1, r2);
}, c.toArray(new Characteristics[c.size()]));
}
with the following Pair
class:
public class Pair<T, U> {
private final T first;
private final U second;
public Pair(T first, U second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public U getSecond() {
return second;
}
}