在Java中进行空检查的最优雅方式是什么?

时间:2017-11-27 17:40:26

标签: java nullpointerexception optional nullable

举一个例子,假设我们有一个类似下面的代码:

String phone = currentCustomer.getMainAddress().getContactInformation().getLandline()

我们知道Java中没有elvis操作符并且像这样捕获NPE:

String phone = null;
try {
    phone = currentCustomer.getMainAddress().getContactInformation().getLandline()
} catch (NullPointerException npe) {}

不是任何人都会建议的。使用Java 8 Optional是一种解决方案,但代码远未明确阅读 - >这些方面的东西:

String phone = Optional.ofNullable(currentCustomer).flatMap(Customer::getMainAddress)
    .flatMap(Address::getContactInformation)
    .map(ContactInfo::getLandline)
    .orElse(null);

那么,还有其他强大的解决方案不会牺牲可读性吗?

编辑:下面已经有了一些好主意,但我们假设模型是自动生成的(每次都不方便更改)或者需要重建的第三方jar内部要修改的来源。

3 个答案:

答案 0 :(得分:4)

问题的“心脏”

此模式currentCustomer.getMainAddress().getContactInformation().getLandline()称为TrainWreck,应予以避免。如果你这样做了 - 不仅你有更好的封装和更少的耦合代码,作为一个“副作用”你不必处理你目前面临的这个问题。

怎么做?

简单,currentCustomer的类应该公开一个新方法:getPhoneNumber()这样用户可以调用:currentCustomer.getPhoneNumber()而不用担心实现细节(由列车公开 - 残骸)。

它能彻底解决我的问题吗?

没有。但现在您可以使用Java 8可选来调整最后一步。与问题中的示例不同,Optionals用于在返回值可能为null时从方法返回,让我们看看它是如何实现的(在类Customer内):

Optional<String> getPhoneNumber() {
    Optional<String> phone = Optional.empty();
    try {
        phone = Optional.of(mainAddress.getContactInformation().getLandline());
    } catch (NullPointerException npe) {
        // you might want to do something here: 
        // print to log, report error metric etc
    }
    return phone;
}

Per Nick的评论如下,理想情况下,方法getLandline()将返回Optional<String>,这样我们就可以跳过吞噬异常的不良做法(当我们可以避免异常时提高它们),这也会使我们的代码更清晰,更简洁:

Optional<String> getPhoneNumber() {
    Optional<String> phone = mainAddress.getContactInformation().getLandline();        
    return phone;
}

答案 1 :(得分:-3)

phone = (currentCustomer.getMainAddress().getContactInformation().getLandline() !=null) ? currentCustomer.getMainAddress().getContactInformation().getLandline() : null;

也许这会奏效吗?有点长,所以我建议也许只是分开它,但它仍然应该是可读的。

答案 2 :(得分:-4)

String s = null;
System.out.println(s == null);

String s = null;
if(s == null)System.out.println("Bad Input, please try again");

如果您的问题是对象为空,那么您应该在问题中明确说明......

PhoneObject po = null;
if(po==null) System.out.println("This object is null");

如果您的问题在于检查该行的所有部分是否为空,那么您应该已经明确了......

if(phone == null) return -1;
Customer c = phone.currentCustomer();
if(c == null)return -1;
MainAddress ma = c.getMainAddress();
if(ma == null) return -1;
ContactInfo ci = ma.getContactInformation();
if(ci == null)return -1;
LandLine ll = ci.getLandline();
if(ll == null)return -1;
else return ll.toNumber()//or whatever method

老实说,编写得好的代码不应该有很多机会返回null。