Java 番石榴 checkNotNull 有什么意义
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26184322/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the point of Guava checkNotNull
提问by Ar3s
I'm pretty new to Guava (let's be honest, I'm not "pretty new", I'm a complete rookie on that subject) and so I decided to go through some documentation and got quite amazed while reading this:
我对番石榴很陌生(老实说,我不是“很新”,我是这个主题的完全新手),所以我决定阅读一些文档,并在阅读本文时感到非常惊讶:
com.google.common.base.Preconditions.checkNotNull(...)
com.google.common.base.Preconditions.checkNotNull(...)
I don't get the point of this method. This means that instead of doing :
我不明白这个方法的重点。这意味着,而不是做:
myObject.getAnything();
(which might cause a NullPointerException
if myObject is null)
(NullPointerException
如果 myObject 为空,这可能会导致一个)
I should use
我应该用
checkNotNull(myObject).getAnything();
which willthrow a NullPointerException
if myObject
is null and return myObject
if it is not null.
这将抛出一个NullPointerException
if myObject
is null 并返回myObject
如果它不为 null。
I'm puzzled and this might be the stupidest question ever but ...
我很困惑,这可能是有史以来最愚蠢的问题,但是......
What is the point of this? Those two lines do the exact same thing as for outcomes given any situations I can think of.
这有什么意义?考虑到我能想到的任何情况,这两行与结果完全相同。
I don't even think that the latter is more readable.
我什至不认为后者更具可读性。
So I must be missing something. What is it?
所以我一定错过了一些东西。它是什么?
采纳答案by yshavit
The idea is to fail fast. For instance, consider this silly class:
这个想法是快速失败。例如,考虑这个愚蠢的类:
public class Foo {
private final String s;
public Foo(String s) {
this.s = s;
}
public int getStringLength() {
return s.length();
}
}
Let's say you don't want to allow null values for s
. (or else getStringLength
will throw a NPE). With the class as-is, by the time you catch that null
, it's too late -- it's very hard to find out who put it there. The culprit could well be in a totally different class, and that Foo
instance could have been constructed a long time ago. Now you have to comb over your code base to find out who could possibly have put a null
value there.
假设您不想允许s
. (否则getStringLength
会抛出 NPE)。就这门课而言,当你发现null
它的时候,已经太晚了——很难找出是谁把它放在那里的。罪魁祸首很可能在一个完全不同的类中,并且该Foo
实例可能是很久以前构建的。现在你必须梳理你的代码库,找出谁可能在null
那里放置了一个值。
Instead, imagine this constructor:
相反,想象一下这个构造函数:
public Foo(String s) {
this.s = checkNotNull(s);
}
Now, if someone puts a null
in there, you'll find out right away-- and you'll have the stack trace pointing you exactly to the call that went wrong.
现在,如果有人把一个null
在那里,你会发现马上-你就会有堆栈跟踪指向正是你走错了电话。
Another time this can be useful is if you want to check the arguments before you take actions that can modify state. For instance, consider this class that computes the average of all string lengths it gets:
如果您想在采取可以修改状态的操作之前检查参数,这可能很有用。例如,考虑这个计算它得到的所有字符串长度的平均值的类:
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;
}
}
Calling accept(null)
will cause an NPE to get thrown -- but not before stringsSeen
has been incremented. This may not be what you want; as a user of the class, I may expect that if it doesn't accept nulls, then its state should be unchanged if you pass a null (in other words: the call should fail, but it shouldn't invalidate the object). Obviously, in this example you could also fix it by getting s.length()
before incrementing stringsSeen
, but you can see how for a longer and more involved method, it might be useful to first check that all of your arguments are valid, and only then modify state:
调用accept(null)
将导致 NPE 被抛出——但在stringsSeen
增加之前不会。这可能不是您想要的;作为该类的用户,我可能期望如果它不接受空值,那么如果传递空值,它的状态应该保持不变(换句话说:调用应该失败,但它不应该使对象无效)。显然,在这个例子中,你也可以通过 get s.length()
before incrementing 来修复它stringsSeen
,但是你可以看到一个更长更复杂的方法,首先检查你的所有参数是否有效,然后才修改状态可能很有用:
public void accept(String s) {
checkNotNull(s); // that is, s != null is a precondition of the method
stringsSeen++;
totalLengthSeen += s.length();
}
回答by maaartinus
myObject.getAnything();
(which might cause a NullPointerException if myObject is null)
myObject.getAnything();
(如果 myObject 为 null,可能会导致 NullPointerException)
No... it willthrow NPE whenever myObject == null
. In Java, there's no chance of calling a method with null
receiver (a theoretical exception are static methods, but they can and should be always called without any object).
不...它会在任何时候抛出 NPE myObject == null
。在 Java 中,没有机会使用null
接收器调用方法(理论上的例外是静态方法,但它们可以并且应该始终在没有任何对象的情况下调用)。
I should use
checkNotNull(myObject).getAnything();
我应该用
checkNotNull(myObject).getAnything();
No you should not. This would be rather redundant (Update).
不,你不应该。这将是相当多余的(更新)。
You should use checkNotNull
in order to fail fast. Without it, you may pass an illegal null
to another method, which passes it further, and so on and so on, where it finally fails. Then you can need some good luck to find out that actually the very first method should have refused null
.
您应该使用checkNotNull
以快速失败。没有它,您可能将非法传递null
给另一个方法,该方法进一步传递它,依此类推,最终失败。然后你可能需要一些好运才能发现实际上第一种方法应该拒绝null
。
The answer by yshavit mentions an important point: Passing an illegal value is bad, but storing it and passing it later is even worse.
yshavit 的回答提到了一个重要的点:传递非法值是不好的,但存储它并稍后传递它更糟。
Update
更新
Actually,
实际上,
checkNotNull(myObject).getAnything()
makes sense, too, as you clearly express your intent to not accept any nulls. Without it, someone could think that you forgot the check and convert it into something like
也有道理,因为您清楚地表达了不接受任何空值的意图。没有它,有人可能会认为您忘记了支票并将其转换为类似的东西
myObject != null ? myObject.getAnything() : somethingElse
OTOH, I don't think the check is worth the verbosity. In a better language, the type system would consider nullability and give us some semantic sugar like
OTOH,我认为支票不值得冗长。在更好的语言中,类型系统会考虑可空性并为我们提供一些语义糖,例如
myObject!!.getAnything() // checkNotNull
myObject?.getAnything() // safe call else null
myObject?.getAnything() ?: somethingElse // safe call else somethingElse
for nullable myObject
, while the standard dot syntax would be allowed only when myObject
is known to be non-null.
对于 nullable myObject
,而只有在myObject
已知为非空时才允许使用标准点语法。
回答by iamcrypticcoder
I have read this whole thread few minutes ago. Nevertheless I was confused why should we use checkNotNull
. Then look over Precondition class doc of Guava and I got what I expected. Excessive use of checkNotNull
will degrade performance definitely.
几分钟前我已经阅读了整篇文章。然而我很困惑为什么我们应该使用checkNotNull
. 然后查看番石榴的前提条件类文档,我得到了我的期望。过度使用checkNotNull
肯定会降低性能。
My thought is checkNotNull
method is worth required for data validation which comes from user directlyor very end API to user interaction. It shouldn't be used in each and every methods of internal API because using it you can't stop exception rather correct your internal API to avoid Exception.
我的想法是checkNotNull
方法对于数据验证是值得的,这些数据验证来自用户直接或最终 API 到用户交互。不应该在内部 API 的每个方法中使用它,因为使用它您不能停止异常,而是更正您的内部 API 以避免异常。
According to DOC:Link
根据DOC:链接
Using checkNotNull:
使用 checkNotNull:
public static double sqrt(double value) {
Preconditions.checkArgument(value >= 0.0, "negative value: %s", value);
// calculate the square root
}
Warning about performance
The goal of this class is to improve readability of code, but in some circumstances this may come at a significant performance cost. Remember that parameter values for message construction must all be computed eagerly, and autoboxing and varargs array creation may happen as well, even when the precondition check then succeeds (as it should almost always do in production). In some circumstances these wasted CPU cycles and allocations can add up to a real problem. Performance-sensitive precondition checks can always be converted to the customary form:
性能警告
此类的目标是提高代码的可读性,但在某些情况下,这可能会带来显着的性能成本。请记住,消息构造的参数值都必须急切地计算,并且自动装箱和可变参数数组创建也可能发生,即使先决条件检查成功(因为它几乎总是在生产中这样做)。在某些情况下,这些浪费的 CPU 周期和分配可能会导致真正的问题。性能敏感的前提条件检查总是可以转换成习惯的形式:
if (value < 0.0) {
throw new IllegalArgumentException("negative value: " + value);
}