Java 8 lambda Void参数

假设我在Java 8中有以下功能接口:

interface Action<T, U> {
U execute(T t);
}
在某些情况下,我需要一个没有参数或返回类型的操作。所以我写 就像这样:

Action<Void, Void> a = () -> { System.out.println("Do nothing!"); };

但是,它给了我编译错误,我需要把它写成

Action<Void, Void> a = (Void v) -> { System.out.println("Do nothing!"); return null;};

这很难看。是否有任何方法可以摆脱Void类型参数?

250911 次浏览

λ:

() -> { System.out.println("Do nothing!"); };

实际上表示接口的实现,如下所示:

public interface Something {
void action();
}

这和你定义的完全不同。这就是为什么你会得到一个错误。

既然你不能扩展你的@FunctionalInterface,也不能引入一个全新的,那么我认为你没有太多的选择。不过,你可以使用Optional<T>接口来表示某些值(返回类型或方法参数)缺失。然而,这并不会使体更简单。

我认为这是不可能的,因为函数定义在您的示例中不匹配。

lambda表达式的计算结果完全为

void action() { }

而你的声明看起来像

Void action(Void v) {
//must return Void type.
}

例如,如果您有以下接口

public interface VoidInterface {
public Void action(Void v);
}

(在实例化时)唯一一种兼容的函数是这样的

new VoidInterface() {
public Void action(Void v) {
//do something
return v;
}
}

缺少return语句或参数都会导致编译器错误。

因此,如果你声明一个函数接受一个参数并返回一个,我认为不可能将它转换为上面提到的任何一个函数。

你所追求的语法可以通过一个小的帮助函数来实现,它将Runnable转换为Action<Void, Void>(例如,你可以将它放在Action中):

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"));

这是不可能的。具有非void返回类型的函数(即使它是Void)必须返回一个值。然而,你可以向Action添加静态方法,允许你“创建”一个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;
}
}

这将允许您编写以下内容:

// 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));

你可以为这种特殊情况创建子接口:

interface Command extends Action<Void, Void> {
default Void execute(Void v) {
execute();
return null;
}
void execute();
}

它使用默认的方法重写继承的参数化方法Void execute(Void),将调用委托给更简单的方法void execute()

结果是,它使用起来更简单:

Command c = () -> System.out.println("Do nothing!");

在函数接口中添加静态方法

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);
}


}

输出

Do nothing!

仅供参考,在方法抛出和/或返回值的情况下,哪个函数接口可以用于方法引用。

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
}

如果Supplier不需要任何参数,但返回一些值,则使用它。

使用Consumer,如果它需要一些东西,但不返回任何东西。

如果Callable返回一个结果并且可能抛出,则使用Callable(最类似于一般CS术语中的Thunk)。

如果Runnable两者都没有且不能抛出,则使用Runnable

我认为这张表简短而有用:

Supplier       ()    -> x
Consumer       x     -> ()
BiConsumer     x, y  -> ()
Callable       ()    -> x throws ex
Runnable       ()    -> ()
Function       x     -> y
BiFunction     x,y   -> z
Predicate      x     -> boolean
UnaryOperator  x1    -> x2
BinaryOperator x1,x2 -> x3

正如在其他答案中所说,这个问题的适当选项是Runnable

与@rado回答参数和描述相同的方法:

/*----------------------
Represents an operation
that accepts two input
arguments and returns no
result.
*/
BiConsumer<T,U>         (T x, U y)  -> ()




/*----------------------
Represents a function
that accepts two arguments
and produces a result.
*/
BiFunction<T,U,R>       (T x, U y)   -> R z




/*----------------------
Represents an operation
upon two operands of the
same type, producing a
result of the same type
as the operands.
*/
BinaryOperator<T>       (T x1, T x2) -> T x3




/*----------------------
A task that returns a
result and may throw an
exception.
*/
Callable<V>             ()    -> V x   throws ex




/*----------------------
Represents an operation
that accepts a single
input argument and returns
no result.
*/
Consumer<T>             (T x)   -> ()




/*----------------------
Represents a function that
accepts one argument and
produces a result.
*/
Function<T,R>           (T x)   -> R y




/*----------------------
Represents a predicate
(boolean-valued function)
of one argument.
*/
Predicate<T>            (T x)   -> boolean




/*----------------------
Represents a portion of
executable code that
don't recieve parameters
and returns no result.
*/
Runnable                ()    -> ()




/*----------------------
Represents a supplier of
results.
*/
Supplier<T>             ()      -> T x


/*----------------------
Represents an operation
on a single operand that
produces a result of the
same type as its operand.
*/
UnaryOperator<T>        (T x1)  -> T x2

字体:

[1] https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html

[2] https://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html

[3] https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Callable.html