-1

I have a Set<Objects> that I want to filter by class to obtain a Set<Foo> (i.e., the subset of Objects that are instanceof Foo). To do this with Java-8 I wrote

Set<Foo> filtered = initialSet.parallelStream().filter(x -> (x instanceof Foo)).map(x -> (Foo) x).collect(Collectors.toSet());

This is throwing a ConcurrentModificationException:

java.util.ConcurrentModificationException
    at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1388)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)

The problem is apparently the collector but I have no clue as to why.

LJ in NJ
  • 196
  • 1
  • 1
  • 12
  • 1
    Have you tried `initialSet.stream()` rather than `initialSet.parallelStream()` ? – ray Sep 01 '21 at 22:23
  • 2
    Parallel stream is not giving you anything here. Concurrency has an overhead. Don't just throw it around because it sounds cool. A better rule of thumb: *never* use parallel stream unless you've actually established there is a bottleneck which a parallel stream will solve. I've worked with Java streams daily for the past 5 years, and I've needed to use parallel streams maybe once. – Michael Sep 01 '21 at 22:50
  • I've tried it both ways (i.e., stream and parallelStream) and had same results. I also broke it into separate parts: Stream stage1 = initialSet.stream(); Stream stage2 = stage1.filter(x -> (x instanceof Foo)); but it had same results. – LJ in NJ Sep 02 '21 at 13:50
  • 4
    The exception indicates that the source collection has been modified while the operation was in progress. Since none of the operations you’ve shown does modify the source collection, the problem must be at the code you haven’t shown. It’s also very interesting that you say you have a `Set`, presumably the `initialSet`, but the exception clearly stems from an operation processing an `ArrayList`… – Holger Sep 02 '21 at 15:59
  • @Holger: you're correct. The stream and collection code was a red herring. The issue turned out to be what was going on elsewhere (see my answer below) – LJ in NJ Sep 02 '21 at 18:00

1 Answers1

-1

Found (and fixed) the problem. The issue is the initialSet. This is being obtained by a call to a 3rd party library (in this case a JGraphT DirectedPseudoGraph instance). The underlying graph was being modified on another thread. Since the initialSet is returned by reference the result is the ConcurrentModificationException.

The real problem is therefore not the stream processing but using a graph that returned a Set that wasn't thread-safe. The solution was to use AsSynchronizedGraph.

LJ in NJ
  • 196
  • 1
  • 1
  • 12
  • 1
    The original question does not show enough detail for anyone to understand this answer. The original question shows no code, and only mentions jgrapht in the tags. – Joris Kinable Sep 03 '21 at 04:26