For example all Lists, Collections2, Sets return a modifiable view - removing from view collection will remove original items.
This works fine:
List<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5, 6, -1, -2, -3, -4);
Collection<Integer> transform = Collections2.filter(
list, new Predicate<Integer>() {
public boolean apply(Integer input) {
return input.intValue() > 0;
}
});
transform.clear();
When I use Iterables and Iterators methods filter/transform I get umodifiable view (i.e all this code reuse UnmodifibleIterator).
This doesn't work:
List<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5, 6, -1, -2, -3, -4);
Iterable<Integer> transform = Iterables.filter(
list, new Predicate<Integer>() {
public boolean apply(Integer input) {
return input.intValue() > 0;
}
});
Iterables.removeIf(transform, Predicates.<Object>alwaysTrue());
I can't find any semantic difference between Iterable and Collection/List/Set/Map so why there are so different implementations in Guava?
The other strange behavior is that the iterator in the first case still doesn't allow the remove operation, but clear or remove/removeAll works fine.
Iterators.transform
(and Iterables.transform
, by extension) does support remove()
. From its Javadoc:
The returned iterator supports
remove()
if the provided iterator does.
Iterators.filter
, however, does not. The reason for this is that there is no way for a filtered iterator to implement hasNext()
without calling next()
on the underlying iterator. Calling hasNext()
on the underlying iterator is not enough, because the next element in that iterator (and every one after that as well, possibly) may not match the Predicate
.
The problem, then, is that calling hasNext()
on the filtered iterator must advance the position of the underlying iterator. This prevents a subsequent call to remove()
from removing the element that was returned by the most recent call to next()
(which is part of the contract of remove()
). Thus, remove()
cannot be supported on a filtered iterator.
The Iterator
for a filtered Collection
has the exact same issue (in fact, it's created using Iterators.filter
). The clear()
and removeAll
methods work because they have full control over the iterator (they are both implemented using Iterables.removeIf
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With