web服务返回一个巨大的XML,我需要访问它的深度嵌套字段。例如:
return wsObject.getFoo().getBar().getBaz().getInt()
问题是getFoo()
、getBar()
、getBaz()
都可能返回null
。
但是,如果我在所有情况下检查null
,代码会变得非常冗长和难以阅读。此外,我可能会错过一些字段的检查。
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();
写下来可以接受吗?
try {
return wsObject.getFoo().getBar().getBaz().getInt();
} catch (NullPointerException ignored) {
return -1;
}
那会被认为是反模式吗?
发布于 2016-06-22 00:00:19
捕获NullPointerException
是做的一件很麻烦的事情,因为它们几乎可以在任何地方发生。很容易从一个bug中得到一个,偶然地抓住它,然后继续,就好像一切都是正常的,从而隐藏了一个真正的问题。处理起来太棘手了,所以最好完全避免.(例如,考虑一下空Integer
的自动取消装箱)。
我建议您使用Optional
类代替。当您想要使用存在或不存在的值时,这通常是最好的方法。
使用它,您可以像这样编写代码:
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
可以使读者清楚地看到这一事实,并且类型系统将确保您不会意外地忘记它。
您还可以访问用于更方便地处理此类值的方法,如map
和orElse
。
缺勤有效还是错误?
但是还要考虑一下,对于中间方法来说,返回null是一个有效的结果,还是一个错误的标志。如果它总是一个错误,那么它可能更好地抛出一个异常,而不是返回一个特殊的值,或者中间方法本身抛出一个异常。
也许会有更多的选择?
另一方面,如果中间方法中没有值是有效的,那么您也可以为它们切换到Optional
?
然后你可以像这样使用它们:
public Optional<Integer> mo(Ws wsObject) {
return wsObject.getFoo()
.flatMap(f -> f.getBar())
.flatMap(b -> b.getBaz())
.flatMap(b -> b.getInt());
}
为什么不选呢?
我能想到的不使用Optional
的唯一原因是,如果这是代码的一个真正的性能关键部分,以及垃圾收集开销最终证明是一个问题。这是因为每次执行代码时都会分配一些Optional
对象,而VM可能无法优化这些对象。在这种情况下,你最初的如果测试可能会更好。
发布于 2016-06-21 23:13:25
我建议考虑Objects.requireNonNull(T obj, String message)
。您可以为每个异常构建包含详细消息的链,如
requireNonNull(requireNonNull(requireNonNull(
wsObject, "wsObject is null")
.getFoo(), "getFoo() is null")
.getBar(), "getBar() is null");
我建议您不要使用特殊的返回值,比如-1
。这不是Java风格。Java设计了异常机制,以避免这种源自C语言的老式方法。
抛出NullPointerException
也不是最好的选择。您可以提供您自己的异常(检查它以保证它将由用户处理,或者不检查以更容易的方式处理它),或者使用来自XML解析器的特定异常。
发布于 2016-06-22 18:28:56
假设阶级结构确实超出了我们的控制范围,我认为,按照问题中的建议,抓住NPE确实是一个合理的解决办法,除非业绩是一个主要考虑因素。一个小的改进可能是封装抛/捕捉逻辑以避免混乱:
static <T> T get(Supplier<T> supplier, T defaultValue) {
try {
return supplier.get();
} catch (NullPointerException e) {
return defaultValue;
}
}
现在您可以简单地做:
return get(() -> wsObject.getFoo().getBar().getBaz().getInt(), -1);
https://stackoverflow.com/questions/37960674
复制