【问题标题】:Android @NonNull usefulnessAndroid @NonNull 的用处
【发布时间】:2016-06-06 21:29:52
【问题描述】:

在阅读和提问like this one 之后,我想知道使用@NonNull Android 支持注释是否有意义。

如果我尝试使用注释为 @NonNullnull 参数调用方法,我会看到来自 Android Studio 的非常小的警告。只是一个警告??

单元测试呢? 我应该使用 null 参数测试该方法吗?如果我这样做...我会得到一个 NullPointerException 并且我的测试将失败

假设我们是两个开发人员。一个在 API 上工作,一个以各种方式测试 API。 作为第二个开发人员,我有责任测试所有内容,以便 API 是防弹的。这就是单元测试的重点,对吧?

那么……第一个使用@NonNull 的开发者有什么意义呢?

如果其他人使用这个 API 和一个空参数...那么这个 API 会抛出一个 NPE。然后他会想:“Urg,那个 API 糟透了……NPE!”他是对的。那个不检查他发送的参数是否为 null 的顽皮开发人员应该面对 IllegalArgumentException,因为这是他的错,而不是 API 的错!

我错了吗?

我认为这些注释会强制编译器显示像attempting to call methodName(@NonNull Object object) with null parameter 这样的错误。

更新 1

好的,谢谢大家的cmets。如果可能的话,我想总结一下我在这里面临的“问题”。以抽象的方式。

我编写了一些代码(一个 API、一个库、一个类等等),其中私有内部代码由提供功能的公共方法包装。

假设这些公共方法将被其他任何人(包括我)使用。 他们中的一些人接受的论点决不能为null,否则一切都会崩溃。

阅读您的 cmets,我面临以下选择:

  1. 继续使用 Java 文档支持的契约/注释 (@NonNull),规定 parameter must not be null。不要检查空参数(否则 IDE 会警告我),并且以某种方式祈祷我永远不会收到空参数;
  2. 与上述相同,但强制执行空检查(即使 IDE 会警告 condition will always be false)并抛出 IllegalArgumentException 而不是在收到空参数时导致 NPE;
  3. 停止使用合约/注释,使用 Java Doc 警告其他开发人员并添加手动检查所有参数。

最后,对于单元测试......我知道我不能有防弹代码,但我喜欢尽可能“猴子测试”我的代码,以防止我的代码出现意外行为以及验证流程(我相信这是单元测试的基础)-

【问题讨论】:

  • 简短回答:它们对 IMO 毫无用处。更长的答案:它们仍在使用中。评论:作为测试人员,您应该在明确告知不要使用“null”测试 apicalls 时使用“null”测试它。
  • @Mackovich 对不起,你错了。您应该测试合同。如果我说一个函数只有在你传入小于 100 的数字时才有效,并且在文档中,那么传入 101 是一个无效的测试。你会说汽车不能通过安全检查,因为它不能在水下工作吗?
  • 很公平 Mackovich 但作为一个编写 API 的人 - 我强烈不同意你的看法。请参阅 Gabe 关于“不能在水下行驶的故障汽车”的评论。使用真实数据进行测试,不要在“用数千颗流星撞击它,看看它是否存活”的情况下测试系统。因为@NotNull 合同真正告诉你的是——它无法生存。但您也是对的 - 它需要进行测试,以便我们了解哪些 other 值也会杀死/崩溃它。
  • @HrundiV.Bakshi 被微软教导并不意味着什么。您绝对应该测试算法的极限(如果算法要处理多达 100 个项目,请使用 100 个项目进行测试)。但是用你知道行不通的数据来测试它是浪费时间。
  • @HrundiV.Bakshi 对于程序,是的,测试无效输入。我们在这里讨论的是一个 API——完全不同的用例。

标签: java android unit-testing android-studio annotations


【解决方案1】:

评论可能为时已晚,但迟到总比没有好:)

有一个Traute javac 插件,它根据方法参数的注释将null-检查插入到生成的字节码中。

这里有一个sample Android project 说明了这一点。

【讨论】:

    【解决方案2】:

    在我看来,您的#2 方法是为 API/库执行此操作的正确方法。使用注解进行静态分析,以防止编译时尝试使用 null 调用方法,并在运行时使用 null 检查以给出有用的异常(并快速失败/防止代码中发生意外事件)如果 null对象被传入。在 null 检查之前使用 //noinspection ConstantConditions 指令告诉 IDE 禁止警告(因为您检查 null 是有正当理由的)。

    随机 NPE 表示库/api 作者可能遗漏了某些内容,并且存在未在其代码中处理的错误。

    IllegalArgumentException(或带有问题描述的 NPE - 在此实例中使用的异常是基于意见的参数)表明调用者在调用方法的方式上犯了错误。

    但最终,在您已经使用 @NonNull 注释之后是否测试 null 将取决于意见和情况。

    【讨论】:

      【解决方案3】:

      其主要目的是为您的同事提供信息。一个人永远不是大型项目的唯一程序员。使用 NotNull 告诉其他程序员,函数的契约意味着你永远不能向它发送 null,所以他们不这样做。否则我可能会做出一个合乎逻辑的假设,即调用 setFoo(null) 将清除 Foo,而 API 无法处理没有 Foo。

      【讨论】:

      • 可能是同事。但是要发布供公众使用的 API 呢?我的意思是,其他用户将调用的所有可公开访问的方法......此外,就我而言,OP 中的两个开发人员是同一个:我。我只想为未来的我(cmets 是为那个 ^^)和任何其他将接手该项目的开发人员编写尽可能多的防弹代码......这只是一个好习惯,对吧?
      • 工作方式相同。它说明合同。有时只说一个函数不为空是有用的。所以可以说我的函数真的不能处理空值——没有好的回退行为。我该怎么办?即使我检查 null,我所能做的就是抛出一个异常。通过添加注释,我至少告诉我的 API 的用户 null 在这里是无效的。它没有任何伤害,并且为足够聪明的程序员提供了有价值的信息来阅读文档。
      • 好吧,我同意通知部分。但是在 Android Studio 上,如果使用注释并检查参数是否为 null,IDE 会警告我条件**将始终为假**因此我的帖子的原因:)
      • 在 IDE 上将只是一个警告,但开发人员在键入代码时会立即看到一个警告。这比编译->运行->崩溃更好。此外,根据 ProGuard 配置,它会导致编译失败并给出警告,即它不能为空。这又是一个比 compile->run->crash 更好的方案。
      猜你喜欢
      • 2019-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-01
      相关资源
      最近更新 更多