【问题标题】:Making sense of non-null and nullability annotations理解非空和可空性注释
【发布时间】:2017-02-24 20:25:56
【问题描述】:

我不清楚我们如何正确使用有关可为空的注释,即 NonNull 和 Nullable。
我对以下内容不太满意:

public void foo(@NonNull ArrayList<CustomObject> list) {  
   CustomObject o = list.get(0);  //etc
}  

1) 防御性地声明非空代码是没有意义的吗?
2)使用此类注释的最有效方法是什么?例如。举个例子
- 使用构建器模式时应该如何使用它们或
- 定义具体类的接口来实现时?实现类的方法应该也包含注解还是假定它?
3)在上面的sn-p中有没有办法定义非空非空?

【问题讨论】:

  • 当我知道一个变量保证不为空时,我通常使用@NonNull。据我所知,它对编译后的代码没有影响,但会抑制 IDE 中的所有“可能是null”警告。相反,我使用@Nullable,在某些情况下我希望一个变量为空。
  • @MichaelDodd:在审查代码时,这不是为了您自己的自我记录目的吗? other 开发人员将使用/访问的方法怎么样?实用方法或方法是模块或库的一部分?
  • 我认为文档和可读性是android-annotations 的全部目的。在我的工作团队中,我们广泛使用这些注释来阐明变量可能/不应该是null。同样,如果库方法 a 被这样注释,它会成为关于是否需要 null 检查的建议。
  • @MichaelDodd:是的,预期的行为是什么?声明一个永远不应为 null 的变量,然后在不检查 null 的情况下访问它?或者检查 null 并抛出一个显式的 NPE?还是检查 null 并停止处理并返回一些错误值?
  • 这一切都取决于您的环境。事实上,Kotlin's support of @NonNull 允许在尝试使用 null 时发生编译时错误。在某些环境中,@NonNull 可能会教授防御性编码风格。

标签: java android design-patterns annotations design-by-contract


【解决方案1】:

现在我有适当的时间进行调查,这就是我发现的。

1)

在使用 @NonNull 注释时仍然进行防御性编码是非常有意义的。仅仅因为参数有@NonNull 注解,null 仍然可以在运行时传递。例如,使用如下数据类:

class DataClass {
    @NonNull private String notNullString;

    public DataClass() { notNullString = null; }

    public String toString() { return notNullString; }
}

您将null 分配给@NonNull 变量的IDE will warn,但调用toString() 返回null。为了解决这个问题,以及询问why you're null-checking a @NonNull variable 的IDE 警告,Google 倾向于使用PreConditions.checkNotNull(T) - 请参阅example code

2)

正如 cmets 中提到的,我个人使用注释来指导 null 是否为预期值。我找不到在构建器模式中使用的任何可靠示例,但您可能可以通过在 build() 方法中使用 checkNotNull() 来强制执行此操作,以便任何意外的 null 值抛出 NullPointerException

至于具体的类,由你决定,但我个人会添加它们以保持一致性。

3)

鉴于上述情况,我会这样做:

public void foo(@NonNull ArrayList<CustomObject> list) {
    checkNotNull(list, "List is null!");
    if (!list.isEmpty()) {  
        CustomObject o = list.get(0);  //etc
    }
}  

【讨论】:

  • 在我看来,我期待注释的目的是通过减少对 null 的无数检查来促进按合同设计的设计,从而稍微优化(更少的 if)和更简洁的代码。如果我们无论如何都要检查 null ,那么推理似乎太复杂了。我知道它有助于记录事物,但这最终取决于人们如何看待@NonNull。我说得通吗?
  • 是的,这是有道理的。在理想的世界中,应该有一个伴随的annotationProcessor,以确保任何标记为@NonNull 的东西都不会被分配null。但是,它还需要检查是否始终为同一个变量分配默认值,否则uninitialized objects 将成为问题。这会带来一系列新问题。
猜你喜欢
  • 2022-07-07
  • 1970-01-01
  • 2017-01-16
  • 2015-10-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多