【问题标题】:Java 8 lambda Void argumentJava 8 lambda Void 参数
【发布时间】:2015-07-08 20:25:06
【问题描述】:

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

【问题讨论】:

  • 如果你需要一个你定义的动作,这是不可能的。但是,您的第一个示例可能适合 Runnable,这是您正在寻找的 Runnable r = () -&gt; System.out.println("Do nothing!");
  • @BobTheBuilder 我不想使用该帖子中建议的消费者。
  • Matt 的回答使类型工作,但是调用者在得到 null 返回值时会做什么?
  • 您可以祈祷并希望this post 中的建议 2 和 3 被 Java 9 接受!

标签: java lambda java-8 void


【解决方案1】:

使用Supplier,如果它什么都不接受,但返回一些东西。

使用Consumer,如果它需要一些东西,但什么都不返回。

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

使用Runnable,如果它既不做也不能扔。

【讨论】:

  • 作为一个例子,我这​​样做是为了包装“void”返回调用:public static void wrapCall(Runnable r) { r.run(); }。谢谢
  • 漂亮的答案。简短而准确。
  • 不幸的是,如果它必须抛出已检查的异常,则无济于事。
  • 作为此答案的补充,不值得编辑:您还可以使用 BiConsumer(需要 2,返回 0)、Function(需要 1,返回 1)和 BiFunction(需要 2,返回 1)。这些是最重要的了解
  • 是否有类似 Callable(在其 call() 方法中引发异常)但需要任何返回值的东西?
【解决方案2】:

我觉得这张表很短很实用:

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

As said on the other answers, the appropriate option for this problem is a Runnable

【讨论】:

  • 终于!谢谢!
  • 别忘了BiConsumer: x, y -&gt; ()
【解决方案3】:

您所追求的语法可以通过一个将Runnable 转换为Action&lt;Void, Void&gt; 的小辅助函数来实现(例如,您可以将其放在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"));

【讨论】:

  • 这是你能得到的最干净的解决方法,IMO,所以 +1(或在界面本身中使用静态方法)
  • Konstantin Yovkov 下面的解决方案(带有@FunctionalInterface)是一个更好的解决方案,因为它不涉及泛型,也不需要额外的代码。
  • @utomas 抱歉,我没有看到涉及@FunctionalInterface 的答案。他只是说,不可能延长它……
  • 嗨@Matt,对不起。我反应太快了。对于给定的问题,您回答是完全有效的。不幸的是,我的投票被锁定了,所以我无法在这个答案上删除我的 -1。两个注意事项:1. 而不是 Runnable 动作应该采用自定义 @FunctionalInterface 称为 SideEffect 的东西,2. 对此类辅助函数的需求突出表明正在发生一些奇怪的事情,并且可能抽象被破坏了。
【解决方案4】:

lambda:

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

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

public interface Something {
    void action();
}

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

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

【讨论】:

  • 问题是你的Something函数不能是我Action类型的子类型,我不能有两种不同的类型。
  • 技术上他可以,但他说他想避免它。 :)
【解决方案5】:

您可以为这种特殊情况创建一个子接口:

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

【讨论】:

  • 这个 Action 来自哪里? Swing 和 JAX-WX Action 接口都没有这样的通用接口?
  • @luis.espinal: Action&lt;T, U&gt; 在问题中声明.....
  • 哈哈哈,我怎么会错过呢?谢谢!
【解决方案6】:

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

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

因此,如果您声明一个接受参数并返回一个参数的函数,我认为不可能将其转换为上述两者都没有的函数。

【讨论】:

    【解决方案7】:

    这是不可能的。具有非 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));
    

    【讨论】:

      【解决方案8】:

      在你的函数式接口中添加一个静态方法

      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!
      

      【讨论】:

        【解决方案9】:

        仅供参考,在方法抛出和/或返回值的情况下,可以使用哪个功能接口作为方法参考。

        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
        }
        

        【讨论】:

        • 请添加更多上下文。这看起来很有趣,但它的含义并不是很明显。
        猜你喜欢
        • 1970-01-01
        • 2015-11-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-14
        相关资源
        最近更新 更多