como se utiliza forEachRemaining(Consumer<? super E> action) ??? de Iterator

Hola, ¿alguien me podría ejemplificar como utilizar el método forEachRemaining() de la interface Iterator?.
Saludos.

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

Bueno, la idea de tener

Bueno, la idea de tener lambdas en Java 8 es que no se tenga que implementar el closure con una clase anónima.

Así que a partir de Java 8, todas las interfaces que tengan un solo método se pueden escribir con una expresión lambda:

....
Iterator<String> iterator = array.iterator();

iterator.forEachRemaining( t -> System.out.println(t) );

Lo cual, no es nada intuitivo inicialmente, es particular porque la firma del método es:

default void forEachRemaining(Consumer<? super E> action)

Pero si se recuerda la regla que una interfaz que tenga un solo método puede usarse con una expresión lambda será un poco más fácil de identificar. Más aún, en Java 8 se agregó la anotación FunctionalInterface ( http://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html ) para marcar las interfaces que estan pensadas para ser implementadas como lambdas.

La forma en la que se puede leer la expresión lambda es que la parte que esta antes de la flecha es el parametro y lo que está después es lo que se va a hacer:

Así que la parte

t -> System.out.println(t)

Es lo mismo que escribió artezatij antes. De hecho los closures están soportados desde Java 1.2 pero la sintáxis es la de clases anomimas, que como se puede ver son mucho más "engorrosas" de escribir pues se tiene que declarar la clase, e implementar el método de la interfaz:

new Consumer<String> {
    @Overrisde
    public void accept( String t ) {
           System.out.println(t);
     }
}

Para quien usa JavaScript le será familiar el pasar funciones como parametros, esto sería simila al hipotético:

// hipotética implementación en Javascript
iterator.forEachRemaining( function( t ) {
     System.out.println( t );
})

Otra opción que es aún menos obvia, es pasarle la referencia del método que quiere que se invoque cada vez.

iterator.forEachRemaining( System.out::println );

Hay buenas razones para esto, aunque sinceramente no las conozco todas. A mi en particular no me gusta mucho pero se aprecia el poder que esto da. La idea aquí es que se va a iterar y en cada "vuelta" se va a invocar el método que se pasa como parametro ( en este caso los dos "dos puntos" significan, toma de la variable System.out el método println y pasalo como argumento a forEachRemaning para que lo invoque en cada iteración )

Imagen de ezamudio

contravarianza

Y como nota al margen, nótese que el parámetro es de tipo Consumer<? super E>, es decir es contravariante. Esto significa que el consumidor debe aceptar un argumento de tipo E o alguna superclase de E. Por ejemplo para un Iterable<BigDecimal>, se puede usar un consumidor que acepte BigDecimal o Number o bien Object.