usar son que las instrucciones funciones expresiones ejercicios ejemplos como anonimas java lambda anonymous-class java-8

java - son - Clase anónima reemplazada por expresiones lambda



instrucciones lambda java (3)

Tengo un código de muestra que usa Java 8 nueva funcionalidad de flujo (obtenga un rango de valores int 1 .. 20, omita los primeros 9, luego tome los 10 restantes, cada valor int: reduzca en uno y multiplique por 2).

System.out.println(Arrays.toString( IntStream.rangeClosed(1, 20).skip(9).limit(10).map((new IntUnaryOperator() { @Override public int applyAsInt(int operand) { return operand - 1; } }).andThen(new IntUnaryOperator() { @Override public int applyAsInt(int operand) { return operand * 2; } })).toArray()));

El resultado es el siguiente:

[18, 20, 22, 24, 26, 28, 30, 32, 34, 36]

Ahora quiero reemplazar clases anónimas con expresiones Lambda . La siguiente conversión funciona bien (la segunda clase anónima reemplazada con i -> i * 2 expresión lambda) y obtengo el mismo resultado:

System.out.println(Arrays.toString( IntStream.rangeClosed(1, 20).skip(9).limit(10).map((new IntUnaryOperator() { @Override public int applyAsInt(int operand) { return operand - 1; } }).andThen(i -> i * 2)).toArray()));

Sin embargo, cuando reemplazo la primera clase anónima con expresión lambda:

System.out.println( Arrays.toString( IntStream.rangeClosed(1, 20).skip(9).limit(10) .map((v -> v - 1).andThen(i -> i * 2)).toArray()));

No puedo compilar mi código. El error dice Operator ''-'' cannot be applied to ''<lambda parameter>'', ''int''

¿Sabes cómo combinar dos expresiones lambda con IntUnaryOperator.andThen ?

Sé que podría usar ... .limit(10).map(v -> v - 1).map(i -> i * 2).toArray() ... que funciona bien pero me gustaría averiguarlo cómo usar IntUnaryOperator.andThen con lambdas (si es posible).


Debe lanzar explícitamente la primera expresión lambda a IntUnaryOperator. El siguiente código funciona:

System.out.println( Arrays.toString( IntStream.rangeClosed(1, 20).skip(9).limit(10) .map(((IntUnaryOperator) v -> v - 1).andThen(i -> i * 2)).toArray()));


Logré compilar el código como el siguiente (aunque usando versiones experimentales de eclipse):

IntUnaryOperator first = v -> v - 1; IntUnaryOperator second = i -> i * 2; System.out.println(Arrays.toString(IntStream.rangeClosed(1, 20).skip(9) .limit(10).map(first.andThen(second)).toArray()));

Entiendo su interés para poder escribir el código sin declarar first y second ; sin embargo, IntUnaryOperator es un FunctionalInterface y en función de cómo funciona el compilador de Java, un FunctionalInterface necesita tener un "contexto" para poder componerlo de la manera que lo desee. Esta es la razón por la cual con el fragmento de código original, el compilador Java no tiene una forma de asignar su expresión lamda exactamente a una instancia de IntUnaryOperator .

Para una discusión más larga eche un vistazo a este hilo: http://mail.openjdk.java.net/pipermail/jdk8-dev/2013-June/002668.html


Otra solución es usar el IntUnaryOperator.identity() estático como un punto de inicio:

IntUnaryOperator.identity().andThen(v -> v - 1).andThen(i -> i * 2)

Con las importaciones estáticas también puedes usar identity() .

Si IntUnaryOperator tenía un método estático como ...

static IntUnaryOperator first(IntUnaryOperator op) { return op; }

... podríamos simplemente escribir:

IntUnaryOperator.first(v -> v - 1).andThen(i -> i * 2)