tutorial - Argumento de Java 8 lambda Void
java 8 lambdas pdf (8)
Digamos que tengo la siguiente interfaz funcional en Java 8:
interface Action<T, U> {
U execute(T t);
}
Y para algunos casos necesito una acción sin argumentos o tipo de retorno. Entonces escribo algo como esto:
Action<Void, Void> a = () -> { System.out.println("Do nothing!"); };
Sin embargo, me da un error de compilación, necesito escribirlo como
Action<Void, Void> a = (Void v) -> { System.out.println("Do nothing!"); return null;};
Lo cual es feo.
¿Hay alguna forma de deshacerse del parámetro de tipo
Void
?
Agregue un método estático dentro de su interfaz funcional
package example;
interface Action<T, U> {
U execute(T t);
static Action<Void,Void> invoke(Runnable runnable){
return (v) -> {
runnable.run();
return null;
};
}
}
public class Lambda {
public static void main(String[] args) {
Action<Void, Void> a = Action.invoke(() -> System.out.println("Do nothing!"));
Void t = null;
a.execute(t);
}
}
Salida
Do nothing!
Eso no es posible.
Una función que tiene un tipo de retorno no nulo (incluso si es nula) tiene que devolver un valor.
Sin embargo, podría agregar métodos estáticos a la
Action
que le permitan "crear" una
Action
:
interface Action<T, U> {
U execute(T t);
public static Action<Void, Void> create(Runnable r) {
return (t) -> {r.run(); return null;};
}
public static <T, U> Action<T, U> create(Action<T, U> action) {
return action;
}
}
Eso te permitiría escribir lo siguiente:
// create action from Runnable
Action.create(()-> System.out.println("Hello World")).execute(null);
// create normal action
System.out.println(Action.create((Integer i) -> "number: " + i).execute(100));
La lambda:
() -> { System.out.println("Do nothing!"); };
en realidad representa una implementación para una interfaz como:
public interface Something {
void action();
}
que es completamente diferente a la que has definido. Es por eso que obtienes un error.
Como no puede extender su
@FunctionalInterface
, ni introducir una nueva, entonces creo que no tiene muchas opciones.
Sin embargo, puede usar las interfaces
Optional<T>
para denotar que faltan algunos de los valores (tipo de retorno o parámetro de método).
Sin embargo, esto no hará que el cuerpo lambda sea más simple.
La sintaxis que
Runnable
es posible con una pequeña función auxiliar que convierte un
Runnable
en
Action<Void, Void>
(puede colocarlo en
Action
por ejemplo):
public static Action<Void, Void> action(Runnable runnable) {
return (v) -> {
runnable.run();
return null;
};
}
// Somewhere else in your code
Action<Void, Void> action = action(() -> System.out.println("foo"));
No creo que sea posible, porque las definiciones de funciones no coinciden en su ejemplo.
Su expresión lambda se evalúa exactamente como
void action() { }
mientras que su declaración parece
Void action(Void v) {
//must return Void type.
}
como ejemplo, si tiene la siguiente interfaz
public interface VoidInterface {
public Void action(Void v);
}
el único tipo de función (durante la creación de instancias) que será compatible parece
new VoidInterface() {
public Void action(Void v) {
//do something
return v;
}
}
y la falta de declaración o argumento de devolución le dará un error de compilación.
Por lo tanto, si declara una función que toma un argumento y devuelve uno, creo que es imposible convertirlo en una función que no menciona ninguno de los anteriores.
Puede crear una subinterfaz para ese caso especial:
interface Command extends Action<Void, Void> {
default Void execute(Void v) {
execute();
return null;
}
void execute();
}
Utiliza un
método predeterminado
para anular el método parametrizado heredado
Void execute(Void)
, delegando la llamada al método más simple
void execute()
.
El resultado es que es mucho más simple de usar:
Command c = () -> System.out.println("Do nothing!");
Solo como referencia, qué interfaz funcional se puede usar para referencia de método en casos en que el método arroja y / o devuelve un valor.
void notReturnsNotThrows() {};
void notReturnsThrows() throws Exception {}
String returnsNotThrows() { return ""; }
String returnsThrows() throws Exception { return ""; }
{
Runnable r1 = this::notReturnsNotThrows; //ok
Runnable r2 = this::notReturnsThrows; //error
Runnable r3 = this::returnsNotThrows; //ok
Runnable r4 = this::returnsThrows; //error
Callable c1 = this::notReturnsNotThrows; //error
Callable c2 = this::notReturnsThrows; //error
Callable c3 = this::returnsNotThrows; //ok
Callable c4 = this::returnsThrows; //ok
}
interface VoidCallableExtendsCallable extends Callable<Void> {
@Override
Void call() throws Exception;
}
interface VoidCallable {
void call() throws Exception;
}
{
VoidCallableExtendsCallable vcec1 = this::notReturnsNotThrows; //error
VoidCallableExtendsCallable vcec2 = this::notReturnsThrows; //error
VoidCallableExtendsCallable vcec3 = this::returnsNotThrows; //error
VoidCallableExtendsCallable vcec4 = this::returnsThrows; //error
VoidCallable vc1 = this::notReturnsNotThrows; //ok
VoidCallable vc2 = this::notReturnsThrows; //ok
VoidCallable vc3 = this::returnsNotThrows; //ok
VoidCallable vc4 = this::returnsThrows; //ok
}