Is it possible for a method in Java 8 to determine if an Iterable <Integer> Object is an iterator of PrimitiveIterator.OfInt?

This is my first activity here, I hope that I will behave correctly! My problem: I try to write a set of functions (static methods in a class) that take one or more Iterable<Integer> , and get primitiveIterator.ofInt, providing it with another function that builds another iterator (that is, functions mean creating iterators over differently).

Here is a simple example of what I mean:

 public static FilterIteratorInt filtor(Iterable<Integer> iter, IntPredicate filter) { return new FilterIteratorInt((PrimitiveIterator.OfInt)iter.iterator(),filter); } 

It’s not entirely clear to me whether this can even work, since the iterator returned by the Iterable<Integer> may not be of type PrimitiveIterator.OfInt .

To overcome this potential difficulty, I was looking for a solution that could be either an interface, for example, for example. PrimitiveIterable.OfInt or in any other way to find out if the iterator is really primitive. I searched for quite a while, but usually just looking at the answers to almost my entire question, this time I had to register here to ask this question directly.

This design is designed to avoid boxing / unboxing orgies, as I want the new iterators to be fast enough.

So here are three questions:

  • Is there a way to find out if an iterator derived from an iterable is actually a primitive iterator (so that the function can distinguish and act accordingly) or is there another way to get one?
  • Perhaps it is futile to try to improve performance this way? That is, will (JIT or Java) compilers optimize this anyway, or is boxing / unboxing inevitable in any case under the hood? Here I hope to find out something.
  • Can someone show me another and better solution that can serve the same purpose (i.e. the composition of primitive iterators or any iterators while we are on it)?

Update: Due to Holgers answer, it comes down to the following question nr. 4: If next() is called on PrimitiveInteger.OfInt , it will call the nextInt() method or, in other words: will it automatically return a clean int ? Or will it still cause the sequence of boxing and unboxing?

From the answer below, I am assuming the latter, and this will mean that it is definitely better to deal with nextInt() explicitly.

Assuming this is correct (please tell me if I'm wrong), I used the instanceof method below and explicitly wrapped it if necessary.

+5
source share
1 answer

Well, you could just use iterator instanceof PrimitiveIterator.OfInt for testing, but when the intended operation is forEachRemaining , for efficient processing you will need both IntConsumer and PrimitiveIterator.OfInt , and Consumer<Integer> to handle those iterators that are not instances of PrimitiveIterator.OfInt , and if you implement both in the same class, you don’t need to run the 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 can be avoided when possible. This is part of the PrimitiveIterator.OfInt.forEachRemaining(Consumer<? super Integer>) contract :

Implementation Requirements:

If this action is an instance of IntConsumer, then it is translated into IntConsumer and passed to forEachRemaining (java.util.function.IntConsumer); otherwise, the action adapts to the IntConsumer instance by placing the IntConsumer argument, and then passes to forEachRemaining (java.util.function.IntConsumer).

This does not apply to processing individual elements using hasNext() / next() , but since your code should only execute PrimitiveIterable.OfInt , the initial step is the only place you need to perform adaptation 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 creating this method once, you can use it in all places where you take Iterable , for example

 public static FilterIteratorInt filter(Iterable<Integer> iter, IntPredicate filter) { return new FilterIteratorInt(adapt(iter.iterator()), filter); } 

But note that this “iterator composition” is very similar to rethinking the Stream API (or IntStream API) ...

+4
source

Source: https://habr.com/ru/post/1271722/


All Articles