变量引用与重复get调用以避免空指针

时间:2014-04-17 22:34:40

标签: java nullpointerexception

我的代码中有一个情况,我在其中进行了大约5次链式get调用,并且任何这些get调用都可以返回null值。我希望它不必那样,但这就是我消耗的服务如何返回我请求的对象,所以我必须处理它。

最初,我的代码看起来像这样:

String firstDomain = book.getBookImages().getDomains().getDefaults().getDomain().get(0);

不幸的是,该行容易出现空指针和arraylist超出范围的异常。我知道我必须检查空指针,但我试图决定

一个。这样做效率最高的代码

B中。这样做的最佳代码

一种选择是分配大量引用,然后检查空值。像这样:

BookImages bImages = book.getBookImages();
Domains domains = null;
Defaults defaults = null;
List<String> domain = null;
String firstDomain = null;
if (bImages != null) {
    domains = bImages.getDomains();
    if (domains != null) {
        defaults = domains.getDefaults();
        if (defaults != null) {
            domain = defaults.getDomain();
            if (domain != null && domain.size() > 0) {
                firstDomain = domain.get(0);
            }
        }
    }
}
if (firstDomain == null) {
    throw new IncompleteBookException("The book was incompletely attributed.");
}

我认为这非常有效,但它困扰我有多少行。它超过了它所属方法的长度的两倍。

这是我能想到的另一种选择:

if (book.getBookImages() == null || book.getBookImages().getDomains() == null || book.getBookImages().getDomains().getDefaults() == null || book.getBookImages().getDomains().getDefaults().getDomain() == null || book.getBookImages().getDomains().getDefaults().getDomain().size() < 1 || book.getBookImages().getDomains().getDefaults().getDomain().get(0) == null) {
    throw new IncompleteBookException("The book was incompletely attributed.");
} 

我喜欢这样的事实,那就是只有三行,即使一行非常荒谬,但我不确定Java的运行时或编译器是否会优化那些重复的方法调用。

我也对其他更好的解决方案持开放态度。有谁知道这些选项中的一个或另一个是否会比另一个更好,或者这是一个微观优化,甚至懒得思考它是愚蠢的,我应该只使用对我来说更好看的?对于不同的事情,我可能不得不多次这样做。

5 个答案:

答案 0 :(得分:2)

要遵循您的第二种方法,您可以申请:

    if ((bImages=book.getBookImages()) == null
            || (domains=bImages.getDomains()) == null
            || (defaults=domains.getDefaults()) == null
            || (domain=defaults.getDomain()) == null
            || domain.size() < 1
            || (firstDomain=domain.get(0)) == null) {
        throw new IncompleteBookException("The book was incompletely attributed.");
    } else {
        //here you can use the firstDomain variable, that is set with the correct value
    }

这样做更好,因为你避免了多个(无用的)相同的调用,并且你已经在变量firstDomain中设置了正确的值(当然,只有在没有空的情况下等等......)

答案 1 :(得分:1)

如果代码更长且错误更短,则不必过多担心代码的长度。编程的目标不是编写尽可能短的代码(除了一些比赛等)。

你的第一个(更长的)方式是正确的,即使有点长。

第二种方法将重复调用同一方法。这可能是您可能想要避免的 - 它可能会产生不良影响,而且性能会更差。

答案 2 :(得分:1)

正如Szymon指出的那样,你不应该两次调用同样的方法。

通过将所有嵌套null检查合并为一个来使原始解决方案更具可读性:

        BookImages bImages = null;
        Domains domains = null;
        Defaults defaults = null;
        List<String> domain = null;
        String firstDomain = null;

        if ((bImages = book.getBookImages()) != null
                && (domains = bImages.getDomains()) != null
                && (defaults = domains.getDefaults()) != null
                && (domain = defaults.getDomain() != null
                && domain.size() > 0) {

                        firstDomain = domain.get(0);

        }

答案 3 :(得分:1)

尝试使用布尔方法;他们倾向于使逻辑更简单,更清晰;例如,我会这样做:

public boolean isCompletelyAttributed(BookImages bImages) {
    if (bImages == null) return false;
    if (bImages.getDomains() == null) return false;
    if (bImages.getDomains().getDefaults() == null) return false;
    if (bImages.getDomains().getDefaults().getDomains() == null) return false;

    return bImages.getDomains().getDefaults.getDomains.size() > 0;
}

然后你打电话

if (!isCompletelyAttributed(book.getImages())) {
    throw new IncompleteBookException("The book was incompletely attributed.");
}

我还建议您在布尔方法中使用Nicola或kiruwka的解决方案。我不知道你可以在对它们做逻辑时重新分配变量,但这似乎是一个优雅的解决方案。

答案 4 :(得分:-1)

这是一种简短的方法。但是,嘿,我不知道你所建造的具体细节以及这是否适合你。

try {
    String firstDomain = book.getBookImages().getDomains().getDefaults().getDomain().get(0);
    // operate on firstDomain
} catch (NullPointerException e) {
    throw new IncompleteBookException("The book was incompletely attributed.");
} catch (IndexOutOfBoundsException e) {
    throw new IncompleteBookException("The book was incompletely attributed.");
}

我听说人们关心这类事情的表现,因为VM必须填写NullPointerException的堆栈跟踪。在这种情况下,您已经为IncompleteBookException进行了类似的操作。