Estoy jugando con Java 8 para descubrir cómo funciona como ciudadanos de primera clase. Tengo el siguiente fragmento:
package test;
import java.util.*;
import java.util.function.*;
public class Test {
public static void myForEach(List<Integer> list, Function<Integer, Void> myFunction) {
list.forEach(functionToBlock(myFunction));
}
public static void displayInt(Integer i) {
System.out.println(i);
}
public static void main(String[] args) {
List<Integer> theList = new ArrayList<>();
theList.add(1);
theList.add(2);
theList.add(3);
theList.add(4);
theList.add(5);
theList.add(6);
myForEach(theList, Test::displayInt);
}
}
Lo que intento hacer es pasar método displayInt
a método myForEach
utilizando una referencia de método. Al compilador produce el siguiente error:
src/test/Test.java:9: error: cannot find symbol
list.forEach(functionToBlock(myFunction));
^
symbol: method functionToBlock(Function<Integer,Void>)
location: class Test
src/test/Test.java:25: error: method myForEach in class Test cannot be applied to given ty
pes;
myForEach(theList, Test::displayInt);
^
required: List<Integer>,Function<Integer,Void>
found: List<Integer>,Test::displayInt
reason: argument mismatch; bad return type in method reference
void cannot be converted to Void
El compilador se queja de eso void cannot be converted to Void
. No sé cómo especificar el tipo de interfaz de función en la firma de myForEach
tal manera que el código se compila. Sé que podría simplemente cambiar el tipo de retorno de displayInt
a Void
y luego regresar null
. Sin embargo, puede haber situaciones en las que no sea posible alterar el método que quiero pasar a otro lugar. ¿Hay una manera fácil de reutilizar displayInt
como es?
Block
se cambió para lasConsumer
últimas versiones de la API JDK 8MethodHandle
), y al usar esto, el compilador de Java puede producir código más eficiente, por ejemplo, implementando lambdas sin cierre como métodos estáticos, evitando así la generación de clases adicionalesFunction<Void, Void>
esRunnable
.Runnable
eCallable
interfaces se escribe que se supone que deben usarse junto con hilos . La molesta consecuencia de eso es que algunas herramientas de análisis estático (como Sonar) se quejarán si llama alrun()
método directamente.Cuando necesita aceptar una función como argumento que no toma argumentos y no devuelve ningún resultado (nulo), en mi opinión, es mejor tener algo como
en algún lugar de tu código. En mis cursos de programación funcional, la palabra 'thunk' se usaba para describir tales funciones. Por qué no está en java.util.function está más allá de mi comprensión.
En otros casos, encuentro que incluso cuando java.util.function tiene algo que coincide con la firma que quiero, todavía no siempre se siente bien cuando el nombre de la interfaz no coincide con el uso de la función en mi código. Supongo que es un punto similar que se hace en otra parte aquí con respecto a 'Runnable', que es un término asociado con la clase Thread, por lo que si bien puede tener la firma que necesito, es probable que confunda al lector.
fuente
Runnable
, no permite excepciones marcadas, lo que lo hace inútil para muchas aplicaciones. ComoCallable<Void>
tampoco es útil, debe definir el suyo propio. Feo.Establezca el tipo de retorno en
Void
lugar devoid
yreturn null
O
fuente
Siento que deberías estar usando la interfaz de consumidor en lugar de
Function<T, R>
.Un consumidor es básicamente una interfaz funcional diseñada para aceptar un valor y no devolver nada (es decir, nulo)
En su caso, puede crear un consumidor en otra parte de su código como este:
Luego puede reemplazar su
myForEach
código con el siguiente fragmento:Tratas myFunction como un objeto de primera clase.
fuente