Java 我应该使用先决条件检查来检查中间结果吗?

Java 我应该使用先决条件检查来检查中间结果吗?,java,guava,Java,Guava,Guava提供了帮助函数来检查前提条件,但我找不到帮助函数来检查中间结果 private void foo(String param) { checkNotNull(param, "Required parameter is not set"); int x = get(param); if (x == -1) { throw new RuntimeException("This should never have happened and indica

Guava提供了帮助函数来检查前提条件,但我找不到帮助函数来检查中间结果

private void foo(String param)
{
    checkNotNull(param, "Required parameter is not set");

    int x = get(param);
    if (x == -1) {
        throw new RuntimeException("This should never have happened and indicates a bug.");
    }
}
  • 我是否应该将
    if(…){…}
    部分包装在我自己的助手中
  • 或者我应该使用番石榴的
    checkState
  • 或者我应该查看由于
    param
    而导致的
    get()
    失败,并使用
    checkArgument
  • 我应该在这些情况下使用资产吗
  • 还是我遗漏了什么
如果
get
方法只是将字符串转换为int,那么它应该在那里进行验证,最好抛出一个illegalArgumentException或一些类似的RuntimeException。通过以上内容,您还可以在方法中混合抽象层次。例如,您的
checkNotNull
抽象掉了对
param
的null检查,但是对
param
的检查作为一个int被拆分为
get
方法和
foo
方法。为什么不使用一个CheckPremission类型方法?例如

private void paramShouldBeNonNullInt(String value) {
    if (value == null) throw new IllegalArgumentException("value was null");
    try {
       Integer.parseInt(value)
    } catch (NumberFormatException  e) {
        throw new IllegalArgumentException("value was not an integer");
    }
}

这是一个介于偏好和惯例之间的问题

通常,人们会使用断言来表示编程错误;也就是说,“如果我正确地完成了我的工作,那么非null的
参数
永远不会导致来自
get
的-1,而不管用户输入或其他外力如何。”我几乎将它们视为可选择在运行时验证的注释

另一方面,如果
get
在某些情况下可能返回-1,但该输入无效,那么我通常会抛出
IllegalArgumentException
,而
checkArgument
是一种非常合理的方法。它的一个缺点是,当你后来发现它时,它可能来自几乎任何地方。考虑:

try {
    baz();
    bar();
    foo(myInput);
} catch (IllegalArgumentException e) {
    // Where did this come from!?
    // It could have come from foo(myInput), or baz(), or bar(),
    // or some method that any of them invoked, or really anywhere
    // in that stack.
    // It could be something totally unrelated to user input, just
    // a bug somewhere in my code.
    // Handle it somehow...
}
在重要的情况下——例如,您希望弹出一条有用的提示,提示用户不允许在输入表单中输入
-1
——您可能希望抛出一个自定义异常,以便以后更容易地捕获它:

try {
    baz();
    bar();
    foo(myInput);
} catch (BadUserInputException e) {
    reportError("Bad input: " + e.getMessage());
    log.info("recorded bad user input", e);
}
至于
checkState
,我觉得这听起来不太合适。该异常通常意味着问题是
所处的状态(或应用程序中其他更全局的状态)。发件人:

表示在非法或不适当的时间调用了方法

在您的情况下,a-1永远不合适,因此
checkState
具有误导性。现在,如果是:

if (x == -1 && (!allowNegativeOne()) { ... }
…那么这就更合适了,尽管它仍然有上面提到的
IllegalArgumentException
的缺点


因此,最后一个问题是,您是应该保持
if
的原样,还是使用helper方法。这实际上取决于口味、检查的复杂程度以及使用频率(例如,在其他方法中)。如果检查像
x==-1
一样简单,并且该检查从未通过其他方法执行过(因此代码重用不是问题),那么我只保留
If

首先需要区分契约(例如断言/编程错误)和错误处理(例如,可以而且应该捕获并从中恢复的可恢复异常)

如果您需要检查中间结果,似乎您不信任被调用的服务,您希望确保您的假设成立。对吗?这应该表示为断言,Guava对此没有很好的支持

看看valid4j。在这里和这里找到的

然后我会这样表达代码(使用valid4j对hamcrest matchers的支持):


这里还有一些很好的答案

根据先决条件:

前置条件异常用于表示调用方法已出错。(…)后置条件或其他不变故障不应引发这些类型的异常

所以

我应该将if(…){…}部分包装在我自己的helper中吗

不,现有的设施应该足够好

还是应该使用番石榴的checkState

可能是:如果在调用该方法之前需要从文件中加载参数,那么这将是该类必须如何使用的契约的一部分

或者我应该将get()的失败视为param的结果并使用checkArgument吗

可能是:例如,如果对参数的语法有一些格式限制。(尽管可能会在
get()
中)

我应该在这些情况下使用资产吗

是的。如果不是像上面那样的先决条件检查,那么通常我会在这里使用一个
assert
。别忘了你仍然可以添加一条消息:

assert x != 1 : "Indicates a bug.";
我发现这适合于记录期望并验证类或方法的内部/私有实现


如果你想做一个运行时检查,你可以做
If(…)抛出AssertionError
,但这可能只有在您使用不信任的不可靠代码时才有必要。

您的代码检查数据的方式非常有效,但是您可能希望使用比
RuntimeException
更“具体”的异常-可能是
非法状态异常
,或者您自己的异常之一。通常“这不应该发生“异常应该是AssertionError,而不是RuntimeException。使用assert有点脆弱,因为它依赖于JVM参数……除此之外,您的代码在我看来还不错。使用参数得到-1似乎是一个有效的
IllegalArgumentException
,因此我会使用
checkArgument。”(x!--1,“我的消息”)
get
只是一个例子,请忽略它的语义,还有
checkNotNull
是我希望
如果(…)
部分看起来像什么的一个例子,本质上我只是缺少了一个
checkorhrowruntime()
assert x != 1 : "Indicates a bug.";