Java 什么';番石榴的要点是什么
我对番石榴很陌生(老实说,我不是“很新”,我是这方面的新手),所以我决定浏览一些文档,读到这篇文章时感到非常惊讶: 我不明白这种方法的意义。 这意味着,与其做:Java 什么';番石榴的要点是什么,java,null,guava,preconditions,Java,Null,Guava,Preconditions,我对番石榴很陌生(老实说,我不是“很新”,我是这方面的新手),所以我决定浏览一些文档,读到这篇文章时感到非常惊讶: 我不明白这种方法的意义。 这意味着,与其做: myObject.getAnything(); (如果myObject为null,则可能导致NullPointerException) 我应该用 checkNotNull(myObject).getAnything(); 如果myObject为null,则将抛出NullPointerException,如果不为null,则返回my
myObject.getAnything();
(如果myObject为null,则可能导致NullPointerException
)
我应该用
checkNotNull(myObject).getAnything();
如果myObject
为null,则将抛出NullPointerException
,如果不为null,则返回myObject
我很困惑,这可能是有史以来最愚蠢的问题,但是
这有什么意义?
考虑到我能想到的任何情况,这两条线的作用与结果完全相同
我甚至不认为后者更具可读性
所以我肯定错过了什么。这是什么
myObject.getAnything()代码>(如果myObject为null,则可能导致NullPointerException)
不。。。只要myObject==null
,它就会抛出NPE。在Java中,使用null
receiver调用方法是不可能的(理论上的例外是静态方法,但它们可以而且应该总是在没有任何对象的情况下调用)
我应该使用checkNotNull(myObject).getAnything()代码>
不,你不应该。这将是相当多余的(更新)
您应该使用checkNotNull
以快速失败。没有它,您可能会将非法的null
传递给另一个方法,该方法会进一步传递它,以此类推,最终失败。然后您可能需要一些运气来发现第一个方法实际上应该拒绝null
yshavit的答案提到了一个重要的点:传递非法值是不好的,但是存储它并在以后传递它更糟糕
更新
其实
checkNotNull(myObject).getAnything()
这也是有道理的,因为您清楚地表达了不接受任何空值的意图。如果没有它,有人可能会认为你忘记了支票,并将其转换为
myObject != null ? myObject.getAnything() : somethingElse
奥托,我认为这张支票不值得这么冗长。在A型系统中,考虑了可空性,并给出了一些类似于的语义糖。
myObject!!.getAnything() // checkNotNull
myObject?.getAnything() // safe call else null
myObject?.getAnything() ?: somethingElse // safe call else somethingElse
对于可为null的myObject
,而标准的点语法仅在myObject
已知为非null时才允许使用。其思想是快速失败。例如,考虑这个愚蠢的类:
public class Foo {
private final String s;
public Foo(String s) {
this.s = s;
}
public int getStringLength() {
return s.length();
}
}
假设您不想为s
允许空值。(或者getStringLength
将抛出一个NPE)。对于类,当您捕获到null
时,为时已晚——很难找到是谁把它放在那里的。罪魁祸首很可能在一个完全不同的类中,而Foo
实例可能早就构建好了。现在,您必须仔细检查代码库,找出谁可能在那里输入了null
值
相反,想象一下这个构造函数:
public Foo(String s) {
this.s = checkNotNull(s);
}
现在,如果有人在其中放入一个null
,您将立即发现——堆栈跟踪将准确地指向出错的调用
另一个有用的方法是,如果您想在执行可修改状态的操作之前检查参数,则可以使用该方法。例如,考虑这个类,计算它得到的所有字符串长度的平均值:
public class StringLengthAverager {
private int stringsSeen;
private int totalLengthSeen;
public void accept(String s) {
stringsSeen++;
totalLengthSeen += s.length();
}
public double getAverageLength() {
return ((double)totalLengthSeen) / stringsSeen;
}
}
调用accept(null)
将导致抛出NPE——但不是在stringsSeen
增加之前。这可能不是你想要的;作为该类的用户,我可能希望如果它不接受null,那么如果传递null,它的状态应该保持不变(换句话说:调用应该失败,但不应该使对象无效)。显然,在本例中,您还可以通过在递增stringsSeen
之前获取s.length()
来修复此问题,但您可以看到,对于更长更复杂的方法,首先检查所有参数是否有效,然后才修改状态可能很有用:
public void accept(String s) {
checkNotNull(s); // that is, s != null is a precondition of the method
stringsSeen++;
totalLengthSeen += s.length();
}
几分钟前,我已经读了这整篇文章。尽管如此,我还是感到困惑,为什么我们应该使用checkNotNull
。然后看看番石榴,我得到了我所期望的。过度使用checkNotNull
肯定会降低性能
我的想法是,checkNotNull
方法值得用于数据验证,该验证直接来自用户或终端API到用户的交互。它不应该在内部API的每个方法中都使用,因为使用它您不能停止异常,而应该纠正您的内部API以避免异常
根据文件:
使用checkNotNull:
性能警告
这个类的目标是提高代码的可读性,但在某些情况下
在这种情况下,可能会付出巨大的性能成本。
请记住,消息构造的参数值必须全部为
急切地计算,可能会创建自动装箱和varargs数组
同样,即使先决条件检查成功(应该如此)
几乎总是在生产中进行)。在某些情况下,这些都是浪费
CPU周期和分配加起来就是一个真正的问题。
性能敏感的前提条件检查始终可以转换为
习惯形式:
if(值<0.0){
抛出新的IllegalArgumentException(“负值:”+值);
}
这就像在方法的开头检查该方法的前提条件是否有效一样?准确地说。立即检查非法论点可以确保你以后不必追查它们。此外,每个查看该方法的人都会看到什么是禁止的(当然,它应该被记录在案…。@Juru:是的,这就是为什么它在预条件类中的原因!它不应该更像这个.s=premissions.checkNotNull(s);但是是的,我没有想到储藏箱,打字机
public static double sqrt(double value) {
Preconditions.checkArgument(value >= 0.0, "negative value: %s", value);
// calculate the square root
}
if (value < 0.0) {
throw new IllegalArgumentException("negative value: " + value);
}