我使用x!=null以避免NullPointerException。还有其他选择吗?

if (x != null) {
    // ...
}

当前回答

可以在方法调用之前使用拦截器。这就是面向方面编程所关注的。

假设M1(对象测试)是一个方法,M2是一个在方法调用之前应用方面的方法,M2(对象测试2)。如果test2!=null则调用M1,否则执行另一件事。它适用于所有要应用方面的方法。如果要为实例字段和构造函数应用方面,可以使用AspectJ。对于方法方面,Spring也是最佳选择。

其他回答

!=的另一种选择空检查是(如果你无法在设计上摆脱它):

Optional.ofNullable(someobject).ifPresent(someobject -> someobject.doCalc());

or

Optional.ofNullable(someobject).ifPresent(SomeClass::doCalc);

SomeClass是某个对象的类型。

但是,您无法从doCalc()获取返回值,因此仅对void方法有用。

我喜欢Nat Pryce的文章。以下是链接:

用多态调度避免空值避免使用“告诉,不要问”风格的null

在文章中,还有一个指向Java Maybe Type的Git存储库的链接,我觉得这很有趣,但我不认为单独使用它会降低检查代码膨胀。在互联网上做了一些研究之后,我想主要通过仔细设计可以减少空码膨胀。

有一种很好的方法来检查JDK中的空值。Optional.java有大量解决这些问题的方法。例如:

    /**
     * Returns an {@code Optional} describing the specified value, if non-null,
     * otherwise returns an empty {@code Optional}.
     *
     * @param <T> the class of the value
     * @param value the possibly-null value to describe
     * @return an {@code Optional} with a present value if the specified value
     * is non-null, otherwise an empty {@code Optional}
     */
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }
    /**
     * Return {@code true} if there is a value present, otherwise {@code false}.
     *
     * @return {@code true} if there is a value present, otherwise {@code false}
     */
    public boolean isPresent() {
        return value != null;
    }
    /**
     * If a value is present, invoke the specified consumer with the value,
     * otherwise do nothing.
     *
     * @param consumer block to be executed if a value is present
     * @throws NullPointerException if value is present and {@code consumer} is
     * null
     */
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }

帮助标枪真的非常非常有用。

在Java中避免空检查的最佳方法是正确处理和使用异常。在我的经验中,随着您向前端移动,空检查变得越来越常见和必要,因为它更接近于通过UI提供无效信息的用户(例如,没有值,为字段提交)。

有人可能会争辩说,你应该能够控制UI正在做什么,以免你忘记大多数UI是通过某种类型的第三方库完成的,例如,根据情况或库的不同,它可能会为空白文本框返回NULL或空字符串。

您可以这样组合这两者:

try
{
  myvar = get_user_supplied_value(); 
  if (myvar == null || myvar.length() == 0) { alert_the_user_somehow(); return; };

  process_user_input(myvar);
} catch (Exception ex) {
  handle_exception(ex);
}

人们采取的另一种方法是:

if (myvar && myvar.length() > 0)  { };

你也可以抛出一个异常(这是我更喜欢的)

if (myvar == null || myvar.length() == 0) {
 throw new Exception("You must supply a name!");
};

但这取决于你。

避免不必要的空检查的方法很简单:

您需要知道哪些变量可以为空,哪些变量不能为空,并且您需要对给定变量属于哪一类有信心。

但是,尽管它可以说得很简单,但实现它却很困难。关键在于自信的部分,因为你如何确定变量不能为空?

对此没有快速的解决方法,但这里有一些提示:

干净的代码。能够推理一段代码的行为最重要的一点是,它是以易于理解的方式编写的。根据变量所代表的内容命名变量,根据它们所做的内容命名方法,应用单一责任原则(SOLID中的S:http://en.wikipedia.org/wiki/SOLID_(object-oriented_design),这意味着每一段代码都应该有一个单独的责任,并且不做任何其他事情)。一旦你的代码是干净的,那么你就更容易理解它,也更容易理解多个代码层。对于杂乱的代码,试图理解一个方法的作用可能会让你忘记当初为什么要读这个方法。(提示:阅读罗伯特·C·马丁的《清洁代码》)避免返回空值。如果空值会使程序无法正常运行,请改为抛出异常(确保添加适当的错误处理)。返回空值可能是可接受的情况,例如,尝试从数据库中获取对象。在这些情况下,编写处理空值的代码,并在您的耳朵后面记下,这里有可能返回空值的内容。处理返回的null值,使其尽可能接近返回null的方法的调用方(不要盲目地将其传递回调用链)永远不要将显式空值作为参数传递(至少不要跨类传递)。如果您曾经处于传递空参数是唯一选项的位置,那么创建一个不包含此参数的新方法是一种方法。验证您的输入!确定应用程序的“入口点”。它们可以从Web服务、REST服务、远程EJB类、控制器等所有内容。对于这些入口点中的每个方法,问问自己:“如果此参数为空,此方法是否正确执行?”如果答案为否,请添加Validate.notNull(someParam,“当someParam为空时无法运行!”);。如果缺少必需的参数,这将引发IllegalArgumentException。在入口点进行这种类型的验证的好处是,您可以很容易地在从入口点执行的代码中假设该变量永远不会为空!此外,如果这失败了,在入口点,调试会比代码深处出现NullPointerException要容易得多,因为这样的失败只能意味着一件事:客户端没有向您发送所有必需的信息。在大多数情况下,您希望验证所有输入参数,如果您发现自己处于需要允许大量空值的位置,这可能是接口设计不良的标志,需要进行重构/添加以满足客户机的需要。使用集合时,返回一个空集合而不是空集合!使用数据库时,请使用非空约束。这样,您就知道从数据库中读取的值不能为空,并且不必检查它。构造代码并坚持执行。这样做可以让您对代码的行为做出假设,例如,如果应用程序的所有输入都经过验证,那么您可以假设这些值永远不会为空。如果您还没有这样做,请编写代码的自动测试。通过编写测试,您将对代码进行推理,并且您也将更加确信它确实做到了它应该做的事情。此外,自动化测试通过让您立即知道这段代码没有做以前的事情来防止重构过程中的错误。

当然,您仍然需要进行空检查,但它可以降到最低限度(即,知道您可能会得到空值,而不是到处都是空值)。当谈到空检查时,我实际上更喜欢使用三元运算符(但要小心使用,当您开始嵌套它们时,它们会变得非常混乱)

public String nullSafeToString(final Object o) {
    return o != null ? o.toString() : "null";
}