假设我在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类型参数?


当前回答

这是不可能的。具有非Void返回类型的函数(即使它是Void)必须返回一个值。然而,你可以添加静态方法的动作,让你“创建”一个动作:

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

其他回答

你所追求的语法是可以用一个小的帮助函数将一个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 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
}

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

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语句或参数都会导致编译器错误。

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

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

如果它获取一些东西,但不返回任何东西,则使用Consumer。

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

如果Runnable既不做也不能抛出,则使用Runnable。

λ:

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

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

public interface Something {
    void action();
}

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

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