【问题标题】:what does the lambda expression in orElseThrow substitute?orElseThrow 中的 lambda 表达式替代了什么?
【发布时间】:2020-01-31 18:07:42
【问题描述】:

我们来看一些简单的示例代码:

Employee employee = repository.findById(id).orElseThrow(() -> new EmployeeNotFoundException(id));

据我了解,lambda是用来创建函数接口的子类(只有1个方法),空括号表示该方法没有参数。

但是在 orElseThrow 中调用了什么方法需要 lambda?我以为是OptionalException

所以我的问题是:如果没有 lambda 调用,这会是什么样子?

员工类:

class Employee {

    private Long id;
    private String name;
    private String role;

    Employee() {}

    Employee(String name, String role) {
        this.name = name;
        this.role = role;
    }
}

以及异常类:

class EmployeeNotFoundException extends RuntimeException {

    EmployeeNotFoundException(Long id) {
        super("Could not find employee " + id);
    }
}

编辑:我对如何为 lambda 表达式编写一个有效的、可编译的替换很感兴趣。 现在我在

        Employee employee = repository.findById(id).orElseThrow(
            new Supplier<Throwable>() {
                @Override
                public Throwable get() {
                    return new EmployeeNotFoundException(id);
                }
            }
        )

但这是不对的,因为现在我需要将异常添加到方法签名中,而使用 lambda 时并非如此。它表明我不知道如何手动实现供应商类而不是通过使用 lambdas 跳过所有这些

【问题讨论】:

  • 在提问之前您进行了哪些搜索和研究?例如,查看the documentation?请在先进行搜索和研究时,告诉我们您发现了什么以及它是如何不足的。它可以提出更好的问题 - 并获得更好的答案,所以这是为了你自己。
  • 我已经阅读了文档,但是我的 Java 知识有点生疏,我很难理解到底是什么被替换了。我不知道如何在没有 lambda 的情况下编写 orElseThrow,例如将供应商作为匿名类放在那里

标签: java exception lambda optional


【解决方案1】:

我没有测试过,但我相信为了避免处理一般的Throwable(通过在您的方法签名中声明它或在您的封闭方法中捕获它),您需要提供Supplier&lt;RuntimeException&gt; 或类似的比RuntimeException 更具体的类型。例如:

    Employee employee = repository.findById(id).orElseThrow(
        new Supplier<EmployeeNotFoundException>() {
            @Override
            public EmployeeNotFoundException get() {
                return new EmployeeNotFoundException(id);
            }
        }
    );

由于EmployeeNotFoundExceptionRuntimeException,因此是未经检查的异常,因此编译器不会关心您是否处理异常。

您至少部分正确地阅读了文档:我们传递给orElseThrow的是Supplier,所以这是lambda实现的接口,也是我们需要实现的接口,无论我们传递一个方法引用,一个 lambda 或在你的情况下,一个用 new 实例化的对象。 Supplier 是一个接受一个类型参数的通用接口。该文档还告诉我们orElseThrow 需要Supplier&lt;? extends X&gt;,其中X extends Throwable,即XThrowable 的子类型。所以传递Supplier&lt;Throwable&gt; 并没有错,但正如你所经历的,它在其他地方给你带来了一些麻烦。我们可以使用Throwable 的任何子类型来代替。输入RuntimeExceptionEmployeeNotFoundException 可以让我们摆脱麻烦。

不过,当 lambda 工作正常时,我不知道你为什么要这么罗嗦。

链接: Documentation of the Supplier interface

【讨论】:

    【解决方案2】:

    Optional::orElseThrow 接受一个Supplier 并且这个Supplier 用于获取Exception 的一个实例,如果Optional 下面有null 值,它将被抛出。查看Optional::orElseThrow 的实现:

    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (this.value != null) {
            return this.value;
        } else {
            throw (Throwable)exceptionSupplier.get();
        }
    }
    

    它只是检查 value 是否存在,如果不存在 - 它从 Supplier 获取 Execption 实例并抛出它。

    还有表达式:

    () -> new EmployeeNotFoundException(id)
    

    符合Supplier 预期的Optional::orElseThrow 方法-Supplier&lt;? extends X&gt; exceptionSupplier 其中X 扩展Throwable。它甚至可以被提取到单独的变量中:

    Supplier<EmployeeNotFoundException> execptionSupplier = () -> new EmployeeNotFoundException(id);
    Employee employee = repository.findById(id).orElseThrow(execptionSupplier);
    

    【讨论】:

      【解决方案3】:

      orElseThrowOptional 类的一个方法,具有以下签名:

      public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
      

      这意味着您传递的 lambda 表达式必须符合 Supplier&lt;? extends X&gt; 功能接口。 Supplier&lt;T&gt; 函数式接口有一个不接受任何参数并返回 T 实例的方法:T get()

      您的 lambda 表达式 - () -&gt; new EmployeeNotFoundException(id) - 与此功能接口匹配。

      此功能接口的get() 方法用于创建orElseThrow() 将在Optional 为空时抛出的Throwable 实例。

      【讨论】:

        【解决方案4】:

        通过查看可选的 JavaDoc 可以很容易地回答这个问题:

        public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
            if (value != null) {
                return value;
            } else {
                throw exceptionSupplier.get();
            }
        }
        

        lambda 参数是提供要抛出的异常的供应商。

        【讨论】:

          猜你喜欢
          • 2015-01-12
          • 2013-05-26
          • 1970-01-01
          • 1970-01-01
          • 2021-12-24
          相关资源
          最近更新 更多