4

I have a list like following.

List<Model> models = ....

Until now, I was doing like this

List<String> anotherlist = models.parallelStream().map(Model::getName).collect(Collectors.toList());

Now, I created another map

Map<String, Model> modelsMap = new ConcurrentHashMap<String, Model>();
for (final Model model : models) {
   modelsMap.put(model.getId(), model);
}

Is it possible when I create do parallel stream on models list , I can prepare my modelsMap also side by side without have to traverse the models list again? Is parallel stream only bound to one kind of operation?

Tunaki
  • 132,869
  • 46
  • 340
  • 423
Saurabh Kumar
  • 16,353
  • 49
  • 133
  • 212

1 Answers1

5

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;
    }
}
Community
  • 1
  • 1
Tunaki
  • 132,869
  • 46
  • 340
  • 423
  • but here i have to traverse again the list. right ? i want in single traversal of models list generate otherslist and modelsmap. – Saurabh Kumar Nov 23 '15 at 12:24
  • Then you have to write your own `Collector`! – Flown Nov 23 '15 at 12:27
  • 1
    @SaurabhKumar, Tunaki edited the answer, so you can see the single traversal solution. Though I doubt that you will really gain some performance on it. – Tagir Valeev Nov 23 '15 at 12:48
  • 1
    @SaurabhKumar The code looks more complicated but that's because (unfortunately), there is no built-in collector in the API that combines multiple collectors and there is no built-in pair class (although you could (abuse) `Map.Entry` but I'd rather not to). – Tunaki Nov 23 '15 at 12:54
  • @Tunaki : Thanks for your answer. It was very good to know something like this is also possible. Just for the project sake i will go for old school forEach loop since will b easier for other developers to understand well. – Saurabh Kumar Nov 24 '15 at 08:06