Java 为什么';谷歌番石榴先决条件&x27;s checkArgument是否返回值?

Java 为什么';谷歌番石榴先决条件&x27;s checkArgument是否返回值?,java,guava,argument-passing,Java,Guava,Argument Passing,我真的很喜欢guava库允许简单的一行程序检查null: public void methodWithNullCheck(String couldBeNull) { String definitelyNotNull = checkNotNull(couldBeNull); //... } 遗憾的是,对于简单的参数检查,您至少需要两行代码: public void methodWithArgCheck(String couldBeEmpty) { checkArgumen

我真的很喜欢guava库允许简单的一行程序检查null:

public void methodWithNullCheck(String couldBeNull) {
    String definitelyNotNull = checkNotNull(couldBeNull);
    //...
}
遗憾的是,对于简单的参数检查,您至少需要两行代码:

public void methodWithArgCheck(String couldBeEmpty) {
    checkArgument(!couldBeEmpty.isEmpty());
    String definitelyNotEmpty = couldBeEmpty;
    //...
}
不过,可以添加方法,该方法可以执行参数检查,并在检查成功时返回值。以下是检查示例以及如何实施检查:

public void methodWithEnhancedArgCheck(String couldBeEmpty) {
    String definitelyNotEmpty = EnhancedPreconditions.checkArgument(couldBeEmpty, !couldBeEmpty.isEmpty());
    //...
}

static class EnhancedPreconditions {
    public static <T> T checkArgument(T reference, boolean expression) {
        if (!expression) {
            throw new IllegalArgumentException();
        }

        return reference;
    }
}
编辑:接受Nizet的答案,因为我同意他关于副作用和一致性推理的观点。
另外,如果您查看Xaerxess注释,它看起来也会引起其他开发人员的混淆。

我一直不明白的是,为什么
checkNotNull()
首先返回它的参数:

public void foo(String bar) {
    Preconditions.checkNotNull(bar);
    // here, you're sure that bar is not null. 
    // No need to use another variable or to reassign bar to the result 
    // of checkNotNull()
}
我个人忽略了
checkNotNull()
的结果,如上所述。这使得事情和其他返回无效的支票一致

我所看到的唯一优势是,您可以做类似的事情,但我发现它的可读性不如两行:

public String trim(String bar) {
    return Preconditions.checkNotNull(bar).trim();
}
因此,简而言之,我同意您的看法,API有点不一致,但我更希望所有方法都返回void。一个方法应该要么有副作用,要么返回一些东西,但通常应避免同时执行这两种操作。在这里,该方法的目标是产生副作用:抛出异常

编辑:


你的例子确实更有效地解释了为什么返回参数是有用的。但是我仍然倾向于一致性和干净性,而不是在一行中检查和赋值。

checkNotNull返回其参数的最大原因是它可以在构造函数中使用,如下所示:

public Foo(Bar bar) {
  this.bar = checkNotNull(bar);
}

但是,
checkArgument
没有执行类似操作的主要原因是,无论如何,您都必须单独传递参数,而且这似乎不值得——特别是对于更复杂的前提条件检查,它有时在自己的行上更具可读性。如果不能增加可读性,那么某些内容可以是一行程序并不意味着它应该是一行程序。

您可以将valid4j与hamcrest matchers一起使用(在Maven Central上找到,名为org.valid4j:valid4j)

对于先决条件和后决条件:

import static org.valid4j.Assertive.*;

this.myField = require(argument, notNullValue());
this.myInteger = require(x, greaterThan(0));
...
return ensure(result, isValid());
对于输入验证:

import static org.valid4j.Validation.*;


validate(argument, isValid(), otherwiseThrowing(InvalidException.class));
链接:


我不会做像
前置条件.checkNotNull(bar.trim()
这样的事情,而不是简单的
bar.trim()
。在这两种情况下,你都得到了相同的NPE,所以测试什么也买不到,你只是在掩盖一件简单的事情
checkNotNull
用于快速失败,因此您可以避免可能不正确的方法部分执行,并获得较短的堆栈跟踪。如果您将其编写为:
return checkNotNull(bar,“bar可能不为null”)。trim(),这样做就有意义了。无论如何,我不是说应该这样做。相反:我认为
checkNotNull()
应该返回void。@JBNizet我尊重你的论证质量,这就是为什么我不会投反对票。在我看来,checknotNull方法是返回变量的一个非常好的选择,我希望有更多这样的方法(例如,
someInt/Ints.checkNoneZero(someOtherInt)
。我认为这是一种很好的方法,可以突出重要的代码需求,而不会使方法变得不必要的长。我认为这会使代码更具可读性,而不是更不可读。相反,在您的第一个示例中,我根本看不到使用该方法的意义。我有一个用例,其中checkNotNull()返回其参数。对超类构造函数的调用:
super(premissions.checkNotNull(param1))
除了您使用
checkArgument(T ref,boolean expr)
的示例之外,最近还讨论了一个
premissions.checkArgument(T ref,谓词测试)
已被拒绝。您始终可以使用自己的方法创建
预条件2
类。我不知道它确实返回了参数…正在进行“代码高尔夫”重构:-)
import static org.valid4j.Validation.*;


validate(argument, isValid(), otherwiseThrowing(InvalidException.class));