有没有更好的方法在 Java 中进行空检查? [复制]

Posted

技术标签:

【中文标题】有没有更好的方法在 Java 中进行空检查? [复制]【英文标题】:Is there a better way to do an empty check in Java? [duplicate] 【发布时间】:2019-09-01 23:25:15 【问题描述】:

这可能看起来像一个原始问题,或者这可以通过一个我不知道的简单实用程序库方法来完成。

目标是检查嵌套在两个对象下的布尔字段的值。

private boolean sourceWebsite(Registration registration) 
    Application application = registration.getApplication();
    if (application == null) 
        return true;
    

    Metadata metadata = application.getMetadata();
    if (metadata == null) 
        return true;
    

    Boolean source = metadata.getSource();
    if (source == null) 
        return true;
    

    return !source;

我知道这可以在单个 if() 中完成。为了便于阅读,我在这里添加了多个ifs。

有没有一种方法可以简化上述if 语句,并有一个简单的实用程序类,如果父对象或不为空,则返回Boolean source 的值?

【问题讨论】:

从 apache utils 中尝试 StringUtils 【参考方案1】:

你可以这样使用java.util.Optional

private boolean sourceWebsite(Registration registration) 
    return Optional.of(registration)
        .map(Registration::getApplication)
        .map(Application::getMetadata)
        .map(Metadata::getSource)
        .map(source -> !source)
        .orElse(Boolean.TRUE);

简而言之,如果任何 getter 返回 null,这将返回 true,否则返回 !Metadata.source

【讨论】:

Boolean.FALSE::equals 而不是 source -> !source 如果你真的喜欢方法参考 我想你的意思是`Optional.ofNullable()` 对不起,你是对的。我投了赞成票:) 返回类型是boolean所以.orElse(true);会更好。 @user11153 该参数需要一个布尔值。你给它一个布尔值,所以它必须被装箱。不是少一箱,而是多一箱【参考方案2】:

如果其中任何一个为空,则以下将返回 true。如果所有值都不为空,则返回!source

private boolean sourceWebsite(Registration registration) 
      return registration.getApplication() == null 
      ||     registration.getApplication().getMetadata() == null
      ||     registration.getApplication().getMetadata().getSource() == null
      ||    !registration.getApplication().getMetadata().getSource();


更新:

如果您希望每个 getter 不被多次调用,那么您可以为每个对象声明变量,例如

private boolean sourceWebsite(Registration registration) 
      Application application;
      Metadata metadata;
      Boolean source;
      return (application = registration.getApplication()) == null 
      ||     (metadata = application.getMetadata()) == null
      ||     (source = metadata.getSource()) == null
      ||    !source;

 

【讨论】:

c# 的空条件运算符 (?.) 是个好东西... 我看到的一个问题是该模式执行 getApplication 4 次、getMetadata 3 次和 getSource 2 次。如果它们都是微不足道的吸气剂,这可能不是什么大问题。但是,如果它们的实现不是微不足道的(或者更糟糕的是:不是没有副作用),这可能会成为一个问题。 @Philipp 是的。但总的来说,吸气剂是微不足道的。 一般来说,它们应该没有副作用,但这假设您正在使用由知道自己在做什么并遵循良好软件工程原则和Java 最佳实践。在现实世界中,这是一个非常大胆的假设。 @EricDuminil 您通常不能依赖它。当它们是微不足道的 getter 时,JVM 可能 能够优化这些方法调用,但是当它们有一些逻辑时它可能无法做到这一点,而且它肯定无法做到它们有副作用。【参考方案3】:

您可以使用的另一个选项是 try-catch 块。如果你得到一个空指针异常返回 true。

private boolean sourceWebsite(Registration registration) 
    try 
        return !registration.getApplication().getMetadata().getSource();
    
    catch (NullPointerException e) 
        return true;
    

【讨论】:

您不应该对程序逻辑使用异常。应在程序中出现不可恢复状态的情况下使用异常,在这种情况下最好停止整个流程而不是尝试恢复。 总的来说,我同意你的看法(如果不是这么短,这样做可能会使代码更难理解),我觉得在这里使用 Optional 是正确的选择(假设你使用的是足够新的java版本可以访问它)。该问题要求一种无需多次空检查即可处理这些检查的方法。这样就可以了。 @Nzall 异常在程序逻辑中也很有用,例如作为一种非常易读的检查字符串是否解析为与 CaptainObvious 答案非常相似的数字的方法。 备份来自 Nzall 的评论:***.com/a/8255933/6296561 - TL;DR:异常严重 直到 NPE 在其中一种方法中被抛得更深。【参考方案4】:

您可以使用这样的 hacky 方法来做到这一点:

public static Object get(Object o, String... m) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException 
    if (o == null || m.length == 0) 
        return null;
    
    for (String m1 : m) 
        o = o.getClass().getMethod(m1).invoke(o);
        if (o == null) 
            return null;
        
    
    return o;

然后这样称呼它:

Boolean source = (Boolean) get(registration, "getApplication", "getMetadata", "getSource");
return source == null ? false : !source;

但我不会在任何严肃的项目中这样做。

【讨论】:

这在很多方面都是糟糕的代码:速度慢、不受编译器控制、不受 IDE 的重构帮助影响。即使您认识到您不会在任何严肃的项目中使用它。但接下来:有什么意义?没有人会费心发布问题甚至阅读不严肃项目的答案。 如果您将方法作为参数而不是字符串传递,可能会更好一些。它可能看起来有点像return Optional.of(registration).map(Registration::getApplication).map(Application::getMetadata).map(Metadata::getSource),所以你不妨直接使用Optional。不过,我认为你不应该投反对票。这种方法作为思想实验仍然很有趣。

以上是关于有没有更好的方法在 Java 中进行空检查? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

我们如何在 Cassandra 中进行空间查询? Cassandra 是不是有任何 GIS 扩展?

Null-Checks的频率和位置

强制 UILabel 占用 3 行

Java 数组赋值(多个值)

时间复复杂度---关于搜索

有没有更好的方法来检查一个数字是不是是两个数字的范围