在Java方法中是否有一种漂亮的方法来断言前置条件?

在Java方法中是否有一种漂亮的方法来断言前置条件?,java,contract,eiffel,Java,Contract,Eiffel,我的很多函数在声明下面都有一大堆验证代码: if ( ! (start < end) ) { throw new IllegalStateException( "Start must be before end." ); } if(!(开始B,C=> 1或str_d.length()>0 考虑到我的一些函数有很多必须验证的参数,我最终可以写很多boiler plate来验证前提条件。我正在编写一个库,主要供非技术开发人员使用,我们发现验证函数输入是帮助用户正确操作API的

我的很多函数在声明下面都有一大堆验证代码:

if ( ! (start < end) ) {
    throw new IllegalStateException( "Start must be before end." );
    }
if(!(开始<结束)){
抛出新的IllegalStateException(“开始必须在结束之前”);
}
我想精确地指定某些输入的有效范围-例如a>B,C=> 1或str_d.length()>0

考虑到我的一些函数有很多必须验证的参数,我最终可以写很多boiler plate来验证前提条件。我正在编写一个库,主要供非技术开发人员使用,我们发现验证函数输入是帮助用户正确操作API的最佳方法。我们越早提出错误,客户所做的工作就越少

在我的方法中,是否有更优雅的方法来指定前置条件、后置条件(可能还有不变条件)


一位同事告诉我埃菲尔编程语言的一个特性,它允许以非常自然的方式描述前/后/不变条件,而无需重复大量样板代码。Java语言是否有一个附加组件可以让我使用一些这种神奇的东西

如何
断言开始
。请查看。

该包具有类似assert的结构,有助于执行此类条件检查。

可用于此类问题。通过检查不变量,可以拦截方法调用。切入点和通知是以声明方式配置的。并使AOP的使用简单明了


下面是一个。

您可以通过注释和面向方面的编程来实现这一点

如果参数组合不合法,我会使用IllegalArgumentException。我将使用IllegalStateException,它处于阻止该方法工作的状态

可以为异常创建帮助器方法

public static void check(boolean test, String message) {
    if(!test) throw new IllegalArgumentException(message);
}

check(start < end, "Start must be before end.");
公共静态无效检查(布尔测试,字符串消息){
如果(!test)抛出新的IllegalArgumentException(消息);
}
检查(开始<结束,“开始必须在结束之前”);
的类就是为了这个。您通常将其用于静态导入,因此您的示例如下所示:

checkArgument(start < end, "Start must be before end");
与断言语句不同,这些语句不能被禁用。

请查看通过注释为Java提供合同的项目。它提供了前置/后置条件和不变量。与其他Java实现相比,它还正确地处理父类/接口中定义的契约。可以在运行时启用/禁用合同评估

以下是他们网站的代码片段:

import com.google.java.contract.Invariant;
导入com.google.java.contract.Requires;
@不变量(“大小()>=0”)
接口栈{
公共整数大小();
@需要(“大小()>=1”)
公共T pop();
公共无效推送(T obj);
}

对于输入验证,您也可以使用


请注意,应始终启用输入验证。因此,它在概念上与断言检查(例如,在Eiffel中)非常不同,断言检查可以选择打开/关闭——如果我发现自己在一个类中重复相同的锅炉板先决条件检查代码,请参见此相关堆栈溢出问题的答案,我重构代码,通过将重复的代码提取到一个新的(
静态私有
)方法来减少重复并增加抽象。我使用Java-7
Objects.requirennoull
方法进行
null
检查

为简单而巧妙地指出!这很有趣-你能给我举一个Guice中的例子吗?我认为Guice/AOP对于一般的前提条件检查不是一个好的建议。对于大型横切检查(特别是那些你可能只想在测试中进行的检查)来说,这是非常好的,比如“提出请求的人是一个登录用户吗”,但是更具体的检查,比如“aassert start
抛出
AssertionError
-如果我们只想检查方法的参数,这是不正确的
checkArgument()
抛出
IllegalArgumentException
并且在业务外观上正确默认情况下禁用断言(因此不会在生产中运行);将
-ea
传递给JVM参数,以便在开发过程中启用它们近九年后看看我的答案,我肯定会建议使用@ColinD in的答案并使用番石榴。你不必只在单元测试中使用它,您还应该能够在运行时使用它。因为测试库被视为仅用于测试代码,并且不能是生产代码的可传递依赖项。否则,您依赖的库/项目将受到影响。如果您正在构建其他人将使用的SDK,这必须是最佳选择。不需要其他依赖项。:)
checkArgument(start < end, "Start (%s) must be before end (%s)", start, end);
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);
}