Java Play Framework-使用Promise.failure(异常)的方法的接口

Java Play Framework-使用Promise.failure(异常)的方法的接口,java,playframework,playframework-2.0,java-8,Java,Playframework,Playframework 2.0,Java 8,背景 Java接口指定开发的调用方和被调用方之间的契约。例如: public interface SomeContainer<T> { public boolean add(T value) throws SomeException; } 公共接口容器{ 公共布尔加法(T值)抛出一些异常; } 上面的方法必须返回布尔值或抛出给定的异常,而不返回其他值 问题描述 如何对基于播放承诺的方法执行相同的操作?承诺不会“抛出”例外;相反,承诺执行承诺。失败(此处例外)。因此,我的界

背景

Java接口指定开发的调用方和被调用方之间的契约。例如:

public interface SomeContainer<T> {
    public boolean add(T value) throws SomeException;
}
公共接口容器{
公共布尔加法(T值)抛出一些异常;
}
上面的方法必须返回布尔值或抛出给定的异常,而不返回其他值

问题描述

如何对基于播放承诺的方法执行相同的操作?承诺不会“抛出”例外;相反,承诺执行承诺。失败(此处例外)。因此,我的界面不会“抛出”任何东西:

public interface SomeContainer<T> {
    public Promise<boolean> add(T value);
}
公共接口容器{
公共承诺增值(T值);
}
但是,上面的定义并不阻止实现类执行Promise.failure()--这不是一个很好的接口定义

一种可能是返回一个“Result”对象,该对象可以包含布尔值或允许的几个异常之一。然而,这似乎有点骇人听闻,而且仍然不能阻止实现代码调用Promise.failure()

问题


如何编写一个有效的基于Play Promise的接口,其中指定了所有返回值和所有可接受的异常,而不允许任何其他异常?

您所描述的是异常的一个基本限制-它们的规范仅在直接从方法抛出时才起作用。这个问题不是特定于承诺的,它在任何时候都会在一个通用接口中表现出来,这在使用lambdas时尤其重要。考虑做一个<代码>列表。Frace,它不会抛出异常,但通常你会传递一个lambda到它(它将实现java .UTI.Falk.For),如果lambda抛出异常怎么办?答案是,它不能,除非它是一个未经检查的异常,并且无法静态地知道该异常将被抛出给
forEach
的调用方

唯一真正的答案是不要使用异常。如果您与函数式编程纯粹主义者交谈,他们会说永远不要使用异常,而应该使用不相交类型来代替异常。Play的JavaAPI实际上提供了这样一种类型,它是
Play.libs.F。惯例是左边应该是错误,右边应该是值。这就是说,这两种类型的游戏都非常有限,并且不能很好地与自身或其他东西组合。库提供的任何一种类型都更加完整,并且组合良好。如果您重视对类型安全性尽可能严格,特别是对异常,那么这可能就是您的库,即使不使用承诺,将错误编码为返回类型也比异常提供更好的类型安全性,并且使编写和重用错误处理变得非常简单。如果这听起来是一个不错的选择,那么你也应该考虑使用比java更具打字能力的语言,eg Scala。

如果你和我一样,对事情更务实一点,那么你会使用混合方法。在某些情况下,调用方显式处理错误非常重要,在这种情况下,它们应该被编码到类型中,例如表单验证,您不只是想抛出错误,您希望通过呈现包含多条有意义的错误消息的页面来处理它—这是强类型错误处理的一个完美示例,您可以返回一个错误列表,一个用于表单中每个有问题的字段,但不能抛出一个异常列表。在其他情况下,错误确实是异常的事情,通常没有特定的处理策略,相反,它们应该留给堆栈中高层的通用catch all来进行通用处理。例如,如果数据库关闭,通常无法从中恢复。在这些情况下,抛出未经检查的异常并让通用错误处理发挥作用,不会造成任何损失。

谢谢。我也使用混合方法。核心数据库方法传播错误以实现灵活性;高级方法可能会忽略它,只返回错误。我不是Java专家,希望有一种更干净的方法来实现它,但我想这两种类型都必须做到!