Argumento void de Java 8 lambda
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. Así que escribo algo como esto:
Action<Void, Void> a = () -> { System.out.println("Do nothing!"); };
Sin embargo, me da error de compilación, necesito escribirlo como
Action<Void, Void> a = (Void v) -> { System.out.println("Do nothing!"); return null;};
Que es feo. ¿Hay alguna manera de deshacerse del parámetro tipo Void
?
8 answers
La sintaxis que buscas es posible con una pequeña función auxiliar que convierte un Runnable
en Action<Void, Void>
(puedes 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"));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-29 14:15:30
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-12 02:08:51
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.
Dado que no puedes extender tu @FunctionalInterface
, ni introducir uno nuevo, entonces creo que no tienes muchas opciones. Sin embargo, puede usar las interfaces Optional<T>
para indicar que faltan algunos de los valores (tipo de retorno o parámetro de método). Sin embargo, esto no hará que el cuerpo lambda más simple.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-29 13:56:23
Puede crear una sub-interfaz 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 fácil de usar:
Command c = () -> System.out.println("Do nothing!");
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-19 12:09:25
Eso no es posible. Una función que tiene un tipo de retorno no nulo (incluso si es Void
) tiene que devolver un valor. Sin embargo, puede agregar métodos estáticos a Action
que le permite "crear" un 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));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-29 14:10:15
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!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-29 16:15:25
No creo que sea posible, porque las definiciones de función 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 (al instanciar) que será compatibile se parece a
new VoidInterface() {
public Void action(Void v) {
//do something
return v;
}
}
Y la falta de instrucción return o argumento le dará un error de compilador.
Por lo tanto, si declaras una función que toma un argumento y devuelve uno, creo que es imposible convertirlo en una función que no hace nada de lo mencionado anteriormente.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-29 14:03:40
Solo para referencia qué interfaz funcional se puede usar para la referencia del método en los 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
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-03 11:06:42