首页 文章

Java 8 lambda Void参数

提问于
浏览
115

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

8 回答

  • 35

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

    您的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语句或参数会给你一个编译器错误 .

    因此,如果你声明一个带参数并返回一个的函数,我认为不可能把它转换成上面没有提到的函数 .

  • 84

    在功能界面中添加静态方法

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

    Output

    Do nothing!
    
  • 5

    您可以使用一个小帮助函数将 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"));
    
  • 25

    lambda:

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

    实际上代表了一个接口的实现,如:

    public interface Something {
        void action();
    }
    

    这与你定义的完全不同 . 这就是你得到错误的原因 .

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

  • 4

    这是不可能的 . 具有非void返回类型的函数(即使它是 Void )必须返回一个值 . 但是你可以添加静态方法到 Action ,它允许你"create" 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));
    
  • 3

    仅供参考哪个功能接口可用于方法引用,方法抛出和/或返回值 .

    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
    }
    
  • 271

    您可以为该特殊情况创建子接口:

    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!");
    
  • 3

    如果没有任何内容,请使用Supplier,但返回一些内容 .

    如果需要,请使用Consumer,但不返回任何内容 .

    如果它既没有,也可以使用Callable,但可能会抛出(最常见的CS术语中的Thunk) .

    如果它既没有也不能扔,请使用Runnable .

相关问题