首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Null检查链与捕获NullPointerException

Null检查链与捕获NullPointerException
EN

Stack Overflow用户
提问于 2016-06-22 06:57:03
回答 19查看 19.1K关注 0票数 124

web服务返回一个巨大的XML,我需要访问它的深度嵌套字段。例如:

代码语言:javascript
运行
复制
return wsObject.getFoo().getBar().getBaz().getInt()

问题是getFoo()getBar()getBaz()都可能返回null

但是,如果我在所有情况下检查null,代码会变得非常冗长和难以阅读。此外,我可能会错过一些字段的检查。

代码语言:javascript
运行
复制
if (wsObject.getFoo() == null) return -1;
if (wsObject.getFoo().getBar() == null) return -1;
// maybe also do something with wsObject.getFoo().getBar()
if (wsObject.getFoo().getBar().getBaz() == null) return -1;
return wsObject.getFoo().getBar().getBaz().getInt();

写下来可以接受吗?

代码语言:javascript
运行
复制
try {
    return wsObject.getFoo().getBar().getBaz().getInt();
} catch (NullPointerException ignored) {
    return -1;
}

那会被认为是反模式吗?

EN

回答 19

Stack Overflow用户

回答已采纳

发布于 2016-06-22 08:00:19

捕获NullPointerException的一件很麻烦的事情,因为它们几乎可以在任何地方发生。很容易从一个bug中得到一个,偶然地抓住它,然后继续,就好像一切都是正常的,从而隐藏了一个真正的问题。处理起来太棘手了,所以最好完全避免.(例如,考虑一下空Integer的自动取消装箱)。

我建议您使用Optional类代替。当您想要使用存在或不存在的值时,这通常是最好的方法。

使用它,您可以像这样编写代码:

代码语言:javascript
运行
复制
public Optional<Integer> m(Ws wsObject) {
    return Optional.ofNullable(wsObject.getFoo()) // Here you get Optional.empty() if the Foo is null
        .map(f -> f.getBar()) // Here you transform the optional or get empty if the Bar is null
        .map(b -> b.getBaz())
        .map(b -> b.getInt());
        // Add this if you want to return null instead of an empty optional if any is null
        // .orElse(null);
        // Or this if you want to throw an exception instead
        // .orElseThrow(SomeApplicationException::new);
}

为什么要选?

对于可能缺少的值,使用Optional而不是null可以使读者清楚地看到这一事实,并且类型系统将确保您不会意外地忘记它。

您还可以访问用于更方便地处理此类值的方法,如maporElse

缺勤有效还是错误?

但是还要考虑一下,对于中间方法来说,返回null是一个有效的结果,还是一个错误的标志。如果它总是一个错误,那么它可能更好地抛出一个异常,而不是返回一个特殊的值,或者中间方法本身抛出一个异常。

也许会有更多的选择?

另一方面,如果中间方法中没有值是有效的,那么您也可以为它们切换到Optional

然后你可以像这样使用它们:

代码语言:javascript
运行
复制
public Optional<Integer> mo(Ws wsObject) {
    return wsObject.getFoo()
        .flatMap(f -> f.getBar())
        .flatMap(b -> b.getBaz())
        .flatMap(b -> b.getInt());        
}

为什么不选呢?

我能想到的不使用Optional的唯一原因是,如果这是代码的一个真正的性能关键部分,以及垃圾收集开销最终证明是一个问题。这是因为每次执行代码时都会分配一些Optional对象,而VM可能无法优化这些对象。在这种情况下,你最初的如果测试可能会更好。

票数 151
EN

Stack Overflow用户

发布于 2016-06-22 07:13:25

我建议考虑Objects.requireNonNull(T obj, String message)。您可以为每个异常构建包含详细消息的链,如

代码语言:javascript
运行
复制
requireNonNull(requireNonNull(requireNonNull(
    wsObject, "wsObject is null")
        .getFoo(), "getFoo() is null")
            .getBar(), "getBar() is null");

我建议您不要使用特殊的返回值,比如-1。这不是Java风格。Java设计了异常机制,以避免这种源自C语言的老式方法。

抛出NullPointerException也不是最好的选择。您可以提供您自己的异常(检查它以保证它将由用户处理,或者不检查以更容易的方式处理它),或者使用来自XML解析器的特定异常。

票数 15
EN

Stack Overflow用户

发布于 2016-06-23 02:28:56

假设阶级结构确实超出了我们的控制范围,我认为,按照问题中的建议,抓住NPE确实是一个合理的解决办法,除非业绩是一个主要考虑因素。一个小的改进可能是封装抛/捕捉逻辑以避免混乱:

代码语言:javascript
运行
复制
static <T> T get(Supplier<T> supplier, T defaultValue) {
    try {
        return supplier.get();
    } catch (NullPointerException e) {
        return defaultValue;
    }
}

现在您可以简单地做:

代码语言:javascript
运行
复制
return get(() -> wsObject.getFoo().getBar().getBaz().getInt(), -1);
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37960674

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档