Java 8 lambda 无效参数

Java 8 lambda Void argument

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

interface Action<T, U> {
   U execute(T t);
}

在某些情况下,我需要一个没有参数或 return 类型的动作。所以我写 像这样:

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

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

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

这很丑。有什么方法可以去掉 Void 类型参数吗?

拉姆达:

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

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

public interface Something {
    void action();
}

这与您定义的完全不同。这就是您收到错误的原因。

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

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

您的 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 语句或参数都会给您带来编译器错误。

因此,如果您声明一个接受参数的函数并且 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"));

那是不可能的。具有非空 return 类型(即使它是 Void)的函数必须 return 一个值。但是,您可以向 Action 添加静态方法,这样您就可以 "create" a 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();
}

它使用 default method 覆盖继承的参数化方法 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!

仅供参考在方法抛出and/orreturns一个值的情况下,哪些功能接口可以用于方法引用。

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,但是returns一些东西。

如果需要,请使用 Consumer,但 returns 什么都不用。

在通用 CS 术语中使用 Callable if it returns a result and might throw (most akin to Thunk

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

我认为这个 table 简短而有用:

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