Skip to content

Conversation

@nickita-khylkouski
Copy link

Summary

  • Override spliterator() in TransformingSequentialList and TransformingRandomAccessList
  • Delegate to backing list's spliterator via CollectSpliterators.map()
  • Preserves characteristics: SIZED, SUBSIZED, ORDERED, IMMUTABLE, CONCURRENT

Motivation

Lists.transform() with CopyOnWriteArrayList throws ConcurrentModificationException during parallel stream operations because the default AbstractList.spliterator() doesn't inherit the IMMUTABLE characteristic from the backing list.

Before: Lists.transform(cowList, fn).parallelStream() → CME
After: Characteristics preserved, no CME

Implementation

Follows the exact pattern used in Collections2.TransformedCollection.spliterator():

@Override
@GwtIncompatible // Spliterator
public Spliterator<T> spliterator() {
  return CollectSpliterators.map(fromList.spliterator(), 0, function);
}

Testing

  • ListsTest: 5,999 tests passed
  • Collections2Test: 1,300 tests passed
  • CollectSpliteratorsTest: 7 tests passed
  • ✅ All transform-related tests: 548 tests passed
  • ✅ Manual verification with CopyOnWriteArrayList concurrent stress test

Fixes #8165

Override spliterator() in TransformingSequentialList and
TransformingRandomAccessList to delegate to the backing list's
spliterator via CollectSpliterators.map().

This preserves critical characteristics like IMMUTABLE and CONCURRENT
from the source list, fixing ConcurrentModificationException when using
Lists.transform() with CopyOnWriteArrayList in parallel streams.

Fixes google#8165
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lists::transform and probably others do not produce spliterators/iterators with correct characteristics

1 participant