This is my first activity here, I hope I behave correctly! My problem: I am trying to write a collection of functions (static methods in a class) that accept one or several Iterable<Integer>
and obtains the primitiveIterator.ofInt, providing it to another function that constructs yet another iterator (i.e. the functions are meant to compose iterators in various ways).
Here is a simple example of what I have in mind:
public static FilterIteratorInt filtor(Iterable<Integer> iter, IntPredicate filter)
{
return new FilterIteratorInt((PrimitiveIterator.OfInt)iter.iterator(),filter);
}
To me, it is not quite clear whether this can work at all, because the iterator
returned by the Iterable<Integer>
Object might not be of type PrimitiveIterator.OfInt
.
In order to overcome this potential difficulty, I have been looking for a solution, which might either be an Interface like e.g. PrimitiveIterable.OfInt
or any other way to find out whether the iterator is in fact primitive. I have been searching for quite a while, but while usually just browsing answers nearly all of my question, this time I had to register here to ask that question directly.
This construction is meant to avoid boxing/unboxing orgies, since I want the new iterators to be reasonably fast.
So here are three questions:
Update: Due to Holgers answer, it boils down to the following question nr. 4: If next()
is called on a PrimitiveInteger.OfInt
, will this invoke the nextInt()
method, or in other words: Will this automatically end up returning a pure int
? Or will it still cause a boxing and unboxing sequence?
From the answer below I assume the latter, and this would mean it is definitely better to deal with nextInt()
explicitly.
Assuming that this is correct (please tell me if I am wrong), I have used the instanceof
method below and explicitly wrap if required.
Iterator interface provides the following methods: boolean hasNext() - Returns true if the iteration has more elements. E next() - Returns the next element in the iteration. void remove() - Removes from the underlying collection the last element returned by the iterator (optional operation).
hasNext. Returns true if the iteration has more elements. (In other words, returns true if next() would return an element rather than throwing an exception.)
Well, you could simply use iterator instanceof PrimitiveIterator.OfInt
to test, but when the intended operation is forEachRemaining
, you would need both, an IntConsumer
to be passed to the PrimitiveIterator.OfInt
for efficient processing and a Consumer<Integer>
to handle those iterators which are not instances of PrimitiveIterator.OfInt
and if you implement both within one class, you don’t need to perform a test at all, the iterator will do for you:
public static void main(String[] args) {
System.out.println("with Collection (of Integer boxes)");
filterAndPrint(Arrays.asList(1, 2, 3), i -> i>2);
System.out.println("with IntStream (using primitive int values)");
filterAndPrint(() -> IntStream.range(1, 4).iterator(), i -> i>2);
}
interface LoggingUnboxingIntConsumer extends IntConsumer, Consumer<Integer> {
@Override default void accept(Integer t) {
System.out.println(" unboxing " + t);
accept(t.intValue());
}
}
public static void filterAndPrint(Iterable<Integer> i, IntPredicate p) {
i.iterator().forEachRemaining((LoggingUnboxingIntConsumer) (int value) -> {
if(p.test(value)) System.out.println(" value "+value+" matches");
});
}
with Collection (of Integer boxes)
unboxing 1
unboxing 2
unboxing 3
value 3 matches
with IntStream (using primitive int values)
value 3 matches
This demonstrates that boxing operations are avoided when possible. This is part of the contract of PrimitiveIterator.OfInt.forEachRemaining(Consumer<? super Integer>)
:
Implementation Requirements:
If the action is an instance of IntConsumer then it is cast to IntConsumer and passed to forEachRemaining(java.util.function.IntConsumer); otherwise the action is adapted to an instance of IntConsumer, by boxing the argument of IntConsumer, and then passed to forEachRemaining(java.util.function.IntConsumer).
This does not apply to single element processing via hasNext()
/next()
, but since your code is supposed to perform composition of PrimitiveIterable.OfInt
only, the initial step is the only place where adaptation has to be done anyway
public static PrimitiveIterator.OfInt adapt(Iterator<Integer> it) {
return it instanceof PrimitiveIterator.OfInt? (PrimitiveIterator.OfInt)it:
new PrimitiveIterator.OfInt() {
public int nextInt() { return it.next(); }
public boolean hasNext() { return it.hasNext(); }
public Integer next() { return it.next(); }
};
}
After having created this method once, you may use it at all places where you accept an Iterable
, e.g.
public static FilterIteratorInt filter(Iterable<Integer> iter, IntPredicate filter) {
return new FilterIteratorInt(adapt(iter.iterator()), filter);
}
But note that this “iterator composition” looks very much like a reinvention of the Stream API (or IntStream
API specifically)…
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