How to modify collection's elements with a spliterator

666 Views Asked by At

After much searching, I just found that the only operation that is supported by Spliterator is to READ elements from a Collection.

Can someone tell me about another operation in CRUD that can be supported by Spliterator. I tried to modify elements in a Collection using a Spliterator but it didn't work:

    Set<Integer> set = new TreeSet<>();
    set.add(2);
    set.add(3);
    set.add(5);
    set.add(6);
    Spliterator<Integer> si = set.spliterator();
    Spliterator<Integer> sa  = si.trySplit();
    while(sa.tryAdvance(e ->  e= ++e));

    System.out.println("original iterator");
    while(si.tryAdvance(e-> e = ++e));
    System.out.println(set.toString());
2

There are 2 best solutions below

4
On BEST ANSWER

Spliterator cannot modify an underlying Collection, mainly because Spliterator (unlike Iterator) is not a strictly Collection-bound interface.

The definition of Iterator (from Iterator's JavaDoc):

An iterator over a collection. [...]

Iterators allow the caller to remove elements from the underlying collection during the iteration with well-defined semantics.

The definition of Spliterator (from Spliterator's JavaDoc):

An object for traversing and partitioning elements of a source. The source of elements covered by a Spliterator could be, for example, an array, a Collection, an IO channel, or a generator function.


EDIT: I just read the code you posted. In this code, you try to mutate an immutable Integer instance inside a Spliterator call. In this case, neither Iterator nor Spliterator can work, because the elements are immutable.

Use a Stream (or an IntStream) for this, together with a map() followed by collect().

0
On

The problem here as mentioned by the accepted answer is Integer objects are immutable, so neither consuming your set through its iterator or spliterators will work, because you can not modify an integer instance in-place. However, if your objects are considered mutable, you can fetch them through Iterator#next or in the consumer of Spliterator#tryAdvance and modify them as regular mutable objects (e.g: through exposed setters).

As a work around solution, you can stream over your set, mapping each integer instance to a new integer instance with the desired changes, from there you can collect them back into a new TreeSet<Integer>.

final Set<Integer> newSet = set.stream()
    .map(number -> number + 1)
    .collect(Collectors.toCollection(TreeSet::new));