在 Java 中优雅地避免 NullPointerException

Gracefully avoiding NullPointerException in Java

提问人:Yuval Adam 提问时间:6/8/2009 最后编辑:Jon SeigelYuval Adam 更新时间:10/25/2016 访问量:7371

问:

请考虑以下行:

if (object.getAttribute("someAttr").equals("true")) { // ....

显然,这一行是一个潜在的错误,属性可能是,我们将得到一个.因此,我们需要将其重构为以下两种选择之一:nullNullPointerException

第一个选项:

if ("true".equals(object.getAttribute("someAttr"))) { // ....

第二种选择:

String attr = object.getAttribute("someAttr");
if (attr != null) {
    if (attr.equals("true")) { // ....

第一个选项读起来很尴尬,但更简洁,而第二个选项意图明确,但冗长。

在可读性方面,您更喜欢哪个选项?

Java 编码样式 NullPointerException 代码可读性

评论


答:

27赞 victor hugo 6/8/2009 #1

我一直用

if ("true".equals(object.getAttribute("someAttr"))) { // ....

因为虽然它有点难读,但它不那么冗长,而且我认为它的可读性足够强,所以你很容易习惯它

1赞 willcodejavaforfood 6/8/2009 #2

我喜欢选项 1,我认为它足够可读。

顺便说一句,选项 3 是引入一个将默认值作为参数的 getAttribute 方法。

评论

0赞 victor hugo 6/8/2009
这个问题是关于“if”块的,所以关于你的选项 3:“你不能总是依赖该方法永远不会返回 null 值
0赞 willcodejavaforfood 6/8/2009
当然,您可以确保它永远不会返回默认值的 null。
0赞 willcodejavaforfood 6/8/2009
选项 3 就是根据 DRY 将错误处理和 null 检查移动到方法中。
0赞 victor hugo 6/9/2009
我同意,但我的意思是你并不总是测试你写的方法,所以你不能依赖返回值不会为空
0赞 alamar 6/8/2009 #3

Util.isEmpty(string)- returns return “” if , string 否则。 返回!string == null || string.trim().isEmpty()Util.notNull(string)string == nullUtil.isNotEmpty(string)Util.isEmpty(string)

我们有一个约定,对于字符串,语义上意味着真,语义上意味着假。Util.isEmpty(string)Util.isNotEmpty(string)

18赞 laalto 6/8/2009 #4

在第二个选项中,您可以利用短路:&&

String attr = object.getAttribute("someAttr");
if (attr != null && attr.equals("true")) { // ....

评论

1赞 David Pierre 6/8/2009
确实可以,但优化有利于可读性,这总是一个坏主意。
7赞 Jonik 6/8/2009
呵呵,偏向于优化?相反,我认为这比选项 1 更具可读性。
1赞 laalto 6/8/2009
是的 - 风格问题没有明确的答案。这是你已经习惯的。就我个人而言,我已经习惯了这种风格,因为它也适用于许多其他从 C/C++ 派生语法的语言。如果您的组织/项目有代码约定,请遵循其建议。
7赞 gustafc 6/8/2009
它不是“优化”,也不是可读性降低。我认为,有两个 if 子句实际上可读性要低得多,因为你最终得到的嵌套块比你实际需要的要多。双 ifs 还为臭名昭著的 “2ifs1else” 错误打开了一扇窗:“if (a) if (b) print(”a and b“);else print(“不是 a 和 b”);
1赞 Marko 6/8/2009 #5

始终渴望更短的代码,因为两者在功能上是等效的。尤其是在这样不牺牲可读性的情况下。

2赞 Jon Skeet 6/8/2009 #6

在某些情况下,简洁的方法一开始感觉是错误的,但实际上变成了惯用语。这是其中之一;另一个是这样的:

String line;
while ((line = bufferedReader.readLine()) != null) {
  // Use line
}

某种情况下的副作用?不可想象!除了当您识别特定模式时,它基本上比替代品更好。

这种模式是相似的——它在 Java 中非常普遍,我希望任何有相当经验的开发人员都能识别它。结果令人愉快地简洁。(有趣的是,我有时会看到 C# 代码不必要地使用相同的习语 - 相等运算符适用于 C# 中的字符串。

底线:使用第一个版本,并熟悉它。

0赞 alexmeia 6/8/2009 #7

这是一个很好的问题。 我通常使用不优雅的:

if (object.getAttribute("someAttr") != null && object.getAttribute("someAttr").equals("true")) { // ....

(我不会再使用它了)

评论

4赞 Vincent Robert 6/8/2009
好!如果 getAttribute() 真的有副作用怎么办?有时你运行一次,有时你运行两次。
0赞 victor hugo 6/9/2009
我可能会把这个写在我在这里看到的“常见编程错误”问题中
0赞 alexmeia 6/11/2009
感谢您的评论。我知道这不好,我来这里是为了学习这样的东西。还有一个问题:如果 getAttribute() 只是一个标准的 getter 方法,那么这种方法有什么问题——所以没有副作用?
1赞 soulmerge 6/18/2009
+1 我认为有些人不看文字,只看代码。@question评论:以后可能会有副作用。不太可能对吸气剂造成太严重的损坏,但有可能。例如,如果它在下一个版本中返回计算数据,则可能会导致性能损失 - 尤其是当此代码无处不在时。
0赞 alexmeia 7/9/2009
谢谢soulmerge,我理解这个问题。我认为 stackoverflow 非常适合这样的事情。
0赞 m s 3/6/2015 #8

我还有另一个答案;

List<Map<String, Object>> group = jjDatabase.separateRow(db.Select("SELECT * FROM access_user_group  WHERE user_id=1 ;"));

在我的数据库中,“access_user_group”中没有“group_c80”列,因此在 get(0).get(“group_c80”) 中,空指针异常一致。但我通过以下代码处理了它:

for (int j = 1; j < 100; j++) {
                    String rulId="0";//defult value,to privent null pointer exeption in group_c
                    try {
                        rulId = group.get(0).get("group_c" + j)).toString();
                    } catch (Exception ex) {
                        ServerLog.Print( "Handeled error in database for " + "group_c" + (j < 10 ? "0" + j : j) +"This error handeled and mot efect in program");
                        rulId = "0";
                    }}
0赞 juanmf 4/29/2016 #9

这是我的方法,虽然需要一堂课,但它只写了一次:PropertyUtil

/**
 * Generic method to encapsulate type casting and preventing nullPointers.
 * 
 * @param <T>          The Type expected from the result value.
 * @param o            The object to cast.
 * @param typedDefault The default value, should be of Type T.
 * 
 * @return Type casted o, of default.
 */
public static <T> T getOrDefault (Object o, T typedDefault) {
    if (null == o) {
        return typedDefault;
    }
    return (T) o;
}

客户端代码可以这样做:

PropertyUtil.getOrDefault(obj.getAttribute("someAttr"), "").equals("true");

或者,对于列表:

PropertyUtil.getOrDefault(
    genericObjectMap.get(MY_LIST_KEY), Collections.EMPTY_LIST
).contains(element);

或者对于 List 的使用者,这将拒绝 Object:

consumeOnlyList(
    PropertyUtil.getOrDefault(
        enericObjectMap.get(MY_LIST_KEY), Collections.EMPTY_LIST
    )
)

默认值可能是 null 对象模式的 impl https://en.wikipedia.org/wiki/Null_Object_pattern