【问题标题】:Validated variable null warning已验证变量空警告
【发布时间】:2018-02-21 20:22:22
【问题描述】:

在 Eclipse (4.7.2) 中设置 null analysis -> potential null access 给我一个警告。

给定以下代码:

public class Test {

    // validator method
    static boolean hasText(String s) {
        return !(s == null || s.trim().isEmpty());
    }

    public static void main(String[] args) {
        // s could come from anywhere and is null iff the data does not exist
        String s = (new Random().nextBoolean()) ? "valid" : null;
        if (hasText(s)) {
            // Potential null pointer access: The variable s may be null at this location
            System.out.println(s.length());
            // ... do actual stuff ...
        }
    }
}

如何避免潜在的 null 警告? @NotNull 不起作用,因为 null 是有效输入,而输出是 boolean

有没有办法告诉编译器,如果这个验证方法返回 true,那么验证的值是非空的?

有没有更好的方法来处理这样的验证方法?

谢谢。


为清晰起见更新:

数据来自用户输入(来自 xml 或 .properties 文件)并且如果数据确实存在则为空。

从不产生null(例如,将其设置为"")将发明不存在的数据,我不能完全拥有NullString 对象(不能扩展String)来表示不存在的数据。

hasText(String s) 必须能够接受任何此类输入数据,因此必须能够接受null

【问题讨论】:

  • 我不明白你想要什么。我的意思是,您的 hasText 参数是一个字符串 - 不是空值。而你试图通过null 而不是String 调用String s = (new Random().nextBoolean()) ? "valid" : null; 尝试写String s = (new Random().nextBoolean()) ? "valid" : "";
  • @zlakad 如果数据不存在,则字符串可能为空,数据可能来自多种来源,我无法完全创建 NullString 对象来防止字符串可以为空。
  • 好的。为什么不使用Optional<String> mayBeNull;
  • 仅供参考,(s == null || s.trim().isEmpty()) ? false : true 只是 !(s == null || s.trim().isEmpty())s != null && !s.trim().isEmpty() 的简写。
  • @shmosel 哎呀。我刚刚将一个更大的 if-else 压缩到那个三元运算中,我突然想到我应该把它简化成一个布尔表达式。很好的收获。

标签: java eclipse null annotations compiler-warnings


【解决方案1】:

您的代码是安全的(它从不抛出空指针异常),但也许 Eclipse 的分析太弱而无法确定这一点。您应该考虑使用更强大的工具。

Checker FrameworkNullness Checker 可以证明您的代码是安全的。你只需要表达hasText的契约:hasText接受一个可能为null的参数,并且只有当它的参数为非null时才返回true。

这是如何表达的:

@EnsuresNonNullIf(expression="#1", result=true)
static boolean hasText(@Nullable String s) { ... }

(详情请见Javadoc for @EnsuresNonNullIf。)

这是您的完整示例,Nullness Checker 会在没有警告的情况下对其进行验证:

import java.util.Random;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;

public class Test {

    // validator method
    @EnsuresNonNullIf(expression="#1", result=true)
    static boolean hasText(@Nullable String s) {
        return !(s == null || s.trim().isEmpty());
    }

    public static void main(String[] args) {
        // s could come from anywhere and is null iff the data does not exist
        String s = (new Random().nextBoolean()) ? "valid" : null;
        if (hasText(s)) {
            // Potential null pointer access: The variable s may be null at this location
            System.out.println(s.length());
            // ... do actual stuff ...
        }
    }
}

【讨论】:

  • 谢谢!这是我一直在寻找的解决方案。
【解决方案2】:

这个怎么样?

public class Test {

    // validator method
    private static boolean hasText(String s) {
        return s != null && !s.trim().isEmpty();
    }

    public static void main(String[] args) {
        String s = (new Random().nextBoolean()) ? "valid" : null;
        if (s != null && hasText(s)) {
            System.out.println(s.length());
            // ... do actual stuff ...
        }
    }
}

这样,您可以将hasText(String) 方法简化为:

    // validator method
    private static boolean hasText(String s) {
        return !s.trim().isEmpty();
    }

另一种选择是避免产生null 值:

public class Test {

    // validator method
    private static boolean hasText(String s) {
        return !s.trim().isEmpty();
    }

    public static void main(String[] args) {
        String s = (new Random().nextBoolean()) ? "valid" : "";
        if (hasText(s)) {
            System.out.println(s.length());
            // ... do actual stuff ...
        }
    }
}

【讨论】:

  • 我已经更新了我的问题,以便更清楚。不幸的是,我看不到避免数据为空的方法,因此hasText() 必须能够接受空值。这种验证器方法在很多地方都使用过,因此将空检查带出它会有些困难,但要么这样做要么忽略警告可能是我唯一的选择......
猜你喜欢
  • 2014-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多