我的很多函数都在声明之下有一整堆验证代码:
if ( ! (start < end) ) {
throw new IllegalStateException( "Start must be before end." );
}
我想精确地指定某些输入的有效范围 - 例如A&gt; B,C =&gt; 1或str_d.length()&gt; 0.
鉴于我的一些函数有很多必须经过验证的参数,我最终可能会编写大量的样板来验证前置条件。我正在编写一个主要由非技术开发人员使用的库,我们发现验证函数输入是帮助我们的用户正确操作API的最佳方法。我们越早提出错误,客户就越不需要做的工作。
在我的方法中是否有更优雅的方法来指定前置条件,后置条件(以及可能的不变条件)。
一位同事告诉我有关Eiffel编程语言的一个特性,它允许以非常自然的方式描述前/后/不变条件,而无需重复大量的样板代码。是否有Java语言的附加组件,这将允许我使用这些魔术?
答案 0 :(得分:12)
Guava的Preconditions课程就是为了这个。您通常将它与静态导入一起使用,因此您的示例如下所示:
checkArgument(start < end, "Start must be before end");
它还可以轻松地向邮件添加更多信息,如果支票通过,则无需支付String
连接费用。
checkArgument(start < end, "Start (%s) must be before end (%s)", start, end);
与assert
语句不同,这些语句不能被禁用。
答案 1 :(得分:6)
查看通过注释提供Java合同的Cofoja项目。它提供前/后条件和不变量。与其他Java实现相比,它正确处理父类/接口中定义的契约。可以在运行时启用/禁用合同评估。
以下是tutorial的代码段:
import com.google.java.contract.Invariant;
import com.google.java.contract.Requires;
@Invariant("size() >= 0")
interface Stack<T> {
public int size();
@Requires("size() >= 1")
public T pop();
public void push(T obj);
}
答案 2 :(得分:5)
assert start < end
怎么样?看看documentation。
答案 3 :(得分:5)
Aspect oriented programming可用于此类问题。可以拦截方法调用以检查不变量。切入点和建议以声明方式配置。 Spring和Guice直截了当地使用了AOP。
这是一个example in Guice。
答案 4 :(得分:4)
您可以使用注释和面向方面的编程来完成此操作。
如果参数组合不合法,我会使用IllegalArgumentException。我会使用IllegalStateException处于阻止该方法工作的状态。
您可以为异常创建辅助方法。
public static void check(boolean test, String message) {
if(!test) throw new IllegalArgumentException(message);
}
check(start < end, "Start must be before end.");
答案 5 :(得分:1)
对于输入验证,您还可以使用Apache Commons Validator。
请注意,应始终启用输入验证。因此,它在概念上与断言检查非常不同(例如,在Eiffel中),可以选择性地打开/关闭 - 查看相关堆栈溢出问题的答案When should I use Apache Commons' Validate.isTrue, and when should I just use the 'assert' keyword?
答案 6 :(得分:1)
如果我发现自己在一个类中重复相同的样板前置条件检查代码,我重构我的代码以减少重复并通过将重复的代码提取到新的(static private
)方法来增加抽象。我使用Java-7 Objects.requireNonNull
方法进行null
检查。
答案 7 :(得分:-2)
JUnit包具有类似assert的结构,可以帮助进行这样的条件检查。