Java:检查null或允许异常处理

Java:检查null或允许异常处理,java,Java,我想知道使用try/exception来处理空值比使用if语句首先检查空值要花多少钱 提供更多信息。有超过50%的几率获得空值,因为在这个应用程序中。如果未输入数据,则通常为空。。。因此,尝试使用空值进行计算是很常见的 也就是说,如果我在计算之前先使用if语句检查null,而不首先尝试计算,那么它会提高性能吗?或者只让抛出异常并处理异常会降低成本吗 谢谢你的建议:-) 感谢您的宝贵反馈!下面是一个伪代码示例来澄清原始问题: BigDecimal value1 = null //assume va

我想知道使用try/exception来处理空值比使用if语句首先检查空值要花多少钱

提供更多信息。有超过50%的几率获得空值,因为在这个应用程序中。如果未输入数据,则通常为空。。。因此,尝试使用空值进行计算是很常见的

也就是说,如果我在计算之前先使用if语句检查null,而不首先尝试计算,那么它会提高性能吗?或者只让抛出异常并处理异常会降低成本吗

谢谢你的建议:-)


感谢您的宝贵反馈!下面是一个伪代码示例来澄清原始问题:

BigDecimal value1 = null //assume value1 came from DB as null
BigDecimal divisor = new BigDecimal("2.0");

try{
    if(value1 != null){ //does this enhance performance?... >50% chance that value1 WILL be null
        value1.divide(divisor);
    }
}
catch (Exception e){
    //process, log etc. the exception
    //do this EVERYTIME I get null... or use an if statement
    //to capture other exceptions.
}

我建议检查null,不要进行计算,而不要抛出异常

异常应该是“异常”和罕见的,而不是管理控制流的方法


我还建议您与客户就输入参数签订合同。如果允许为空,请详细说明;如果没有,请说明应该传递什么、默认值以及如果传递空值,您承诺返回什么。

如果获得空值的几率大于50%,那么这几乎不是例外


就我个人而言,我想说,如果你期望发生什么事情,你应该为它编写适当的代码——在这种情况下,检查null并做任何适当的事情。我一直认为抛出异常的代价不太便宜,但不能肯定。

如果传递
null
参数是一种例外情况,那么我会抛出
NullPointerException

public Result calculate(Input input) {
    if (input == null) throw new NullPointerException("input");
    // ...
}

如果允许传递
null
,那么我将跳过计算,最终返回
null
。但在我看来,这没什么意义。在第一个实例中传递
null
似乎是调用代码中的一个错误


无论您选择哪种方式,都应该在Javadoc中正确地记录它,以避免API用户感到意外。

Try-and-catch接近“免费”,但抛出可能非常昂贵。通常VM创建者不会优化异常路径,因为它们是异常的(应该很少)

NullPointerException表示程序员错误(RuntimeException),不应被捕获。您不应该捕获NullPointerException,而应该修复代码,使异常不会首先抛出

更糟糕的是,如果您捕获了NullPointerException,并且计算代码中抛出NullPointerException的部分与您期望抛出的部分不同,那么您现在已经掩盖了一个bug


为了完全回答您的问题,我将以一种方式实现它,对其进行概要分析,然后以另一种方式实现它并对其进行概要分析。。。然后,我只使用if语句,避免抛出NullPointerException,而不管哪一个更快,这仅仅是因为上面的一点。

我同意大多数其他回答,即您应该更喜欢null检查而不是try-catch。我已经把他们中的一些投了更高的票

但是你应该尽量避免这种需要

有超过50%的几率获得空值,因为在这个应用程序中。如果未输入数据,则通常为空。。。因此,尝试使用空值进行计算是很常见的

这才是你真正应该解决的问题

提出合理的默认值,以确保计算正常进行,或避免在不提供所需输入数据的情况下调用计算


对于许多标准数据类型和涉及它们的计算,都有合理的默认值。根据其含义,默认数字为0或1,默认字符串和集合为空,并且许多计算都可以正常工作。对于你自己制作的更复杂的对象,请考虑这个模式。

如果你有任何结果或输入不能被程序处理,那么这应该是一个错误。您应该知道您的程序可以处理什么,并且只允许它。对于未来可能出现的情况,如果结果可以处理,但尚未处理,我仍然建议将其视为错误,直到您真正需要该结果。如果有疑问,你不知道,程序不知道,它无法处理,你没有装备你的程序来处理它,所以这是一个错误。这个程序除了停止外,什么也做不了

对于用户输入来说,依赖程序最终崩溃是一个非常糟糕的主意。你不知道它什么时候甚至是否会崩溃。它可能只是做了错误的事情,或者做了十件事情,然后崩溃,这是它不应该做的,如果输入被验证的话也不会做的

就防止自己的错误而言,这是一个复杂的问题。通过测试、消除未知因素、校对、确保准确了解程序的工作方式等,您将需要更多地关注确保工作正常。不过,偶尔也会出现内部处理可能产生不希望的结果的情况

当结果不是给定情况下的错误时,您不处理异常,而是处理null,而不是异常。在这种情况下,结果不是错误。所以你要处理结果而不是错误。再简单不过了。如果您正在捕获异常,然后执行可以使用If执行的操作,例如:

try
    extra = i_need_it(extra_id)
    show('extra', extra)
catch
    show('add_extra')
Object i_want(Object it) throws
    if(it === null)
        throw
    return it;
那就不对了。如果你没有多余的东西,你有一个完全可以接受的行动方案

这样做更好,而且可以让您的意图更加清晰,而不需要额外的赘述:

Something extra = i_want_it(extra_id)
if extra ==== null 
    show('add_extra')
else
    show('extra', extra)
注意,这里您不需要任何特殊的东西来避免捕获另一层的异常。我怎么把试球放在上面是一个坏习惯。您应该只包装引发异常的对象:

Something extra
try
    extra = i_need_it(extra_id)
if extra === null
    show('add_extra')
else
    show('extra', extra)
当你这样想的时候,它只是将null转换为exception,然后再转换回来。这是溜溜球编码

您应该从以下内容开始:

Object i_need_it(int id) throws
直到你
bool does_it_exist(int id)
if(does_it_exist(id))
    Something i_need = i_need_it(id)
void it_must_exist(int id) throws
Object|null get(int id, bool require) throws
Object i_want(Object it) throws
    if(it === null)
        throw
    return it;
void give_me(Object it)
    this.it = Lib<Object>::i_want(it)
void i_get_it(Getter<Object> g)
    this.it = Lib<Object>::i_want(g.gimme())
void i_need_it(Result<Object> r)
    this.it = r.require()
void i_need_it(Object it)
    this.it = it

void i_want_it(Object? it)
    this.it = it