4

I'm having trouble with joining lists created in a "parallelStream()". Here is the situation :

  • I have a List<Pair> that contains pairs of "int" values
  • From each of those pairs, I am generating a List<Edge> using a "parallelStream()"
  • I want to collect & join these lists into a "merged" List<Edge>

What I'd like to do (and I expected it to work, following the last bullet point of this answer) is the following :

List<Edge> edges = pairs.parallelStream()
        .map(p -> align(p.first(), p.second()))
        .collect(ArrayList::new, List::add, List::addAll);

With align() doing CPU-intensive work (which is why I need to "parallelize" it in the first place) and returning a List<Edge>.

The use of collect() prevents me from compiling, giving the following error :

Error: java: incompatible types: cannot infer type-variable(s) R,E (argument mismatch; invalid method reference incompatible types: ArrayList< Edge > cannot be converted to int)

Note that I did manage to make similar (but "uglier" imo) versions work, which confuses me even more:

v1 :

List<List<Edge>> collect = pairs.parallelStream()
        .map(p -> align(p.first(), p.second()))
        .collect(Collectors.toList());
collect.forEach(l -> l.forEach(edges::add));

v2 :

List<Edge> edges = new ArrayList<>();
pairs.parallelStream()
        .map(p -> align(p.first(), p.second()))
        .collect(Collectors.toList()).forEach(edges::addAll);

Can someone help me with this? I would like to avoid giving up and using "v2" ;)

Community
  • 1
  • 1
qdrien
  • 133
  • 1
  • 11

2 Answers2

5

It's not 100% clear, but it looks like you probably want

List<Edge> edges = pairs.parallelStream()
    .flatMap(p -> align(p.first(), p.second()).stream())
    .collect(Collectors.toList());
Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • 1
    Agreed; although I prefer, in this case, to `.map(p -> align(p.first(), p.second())).flatMap(Collection::stream)` :) – fge Mar 24 '16 at 19:37
  • 1
    My feeling is that if you're already writing an explicit lambda, you might as well fold the `.stream()` call in there; if you were using a method reference I might feel differently. – Louis Wasserman Mar 24 '16 at 19:38
  • 1
    Well, I can understand that; however I somehow resent writing too much "lambda code", and therefore aim at keeping such code as minimal as possible. And yes, that's a feeling, too – fge Mar 24 '16 at 19:40
  • Well, SO will never stop to amaze me, thanks a lot, it in fact seems to work. I'll accept your answer when I'll be able to, in ~5min apparently, because you were too fast for SO itself :D. – qdrien Mar 24 '16 at 19:43
3

You can also fix this by replacing List::add with List::addAll as the second argument to collect:

List<Edge> edges = pairs.parallelStream()
        .map(p -> align(p.first(), p.second()))
        .collect(ArrayList::new, List::addAll, List::addAll);
Misha
  • 27,433
  • 6
  • 62
  • 78