NullPointerExceptions (NPE)。空指针异常
NullAway:https://github.com/uber/NullAway
介绍 NullAway
NullAway 的核心是基于开源类型的 NPE 检查器,用于 Java 代码。要使用 NullAway,你必须先在代码(字段,方法参数或返回值为 null)中添加 @Nullable
注释。(由于我们以前使用 Eradicate
,我们已经在我们的代码库中有这些注释。)给定这些注释,NullAway 执行本地的一系列一致性检查,以确保在代码中取消引用的任何指针不能为空。
NullAway 是一个用于查找框架 Error Prone bug 的检查插件。Error Prone 的运行代码检查作为 Java 编译过程标准的一部分。此编译器的集成允许检查编译器已经完成的工作,如代码解析和类型检查。此外,NullAway 和 Error Prone 可直接集成到我们用于 Android 代码的构建工具 Buck 所支持的快速内存并行构建中。因此,NullAway 可以比在正常构建过程之外运行的工具快得多。
我们发现,NullAway 在正常构建时间中只用了很少的开销(约占 10%)。因此,我们配置了 NullAway,不仅仅是在提交队列中运行,而是运行在我们的 Android 代码的每一个版本上。
将 NullAway 整合到我们所有的 Java 构建中的价值表现在以下三个方面:
立即反馈:集成到所有版本中,使开发人员能够在引入潜在的 NPE 时立即获得反馈,而不必等待提交队列。
没有 NPE 检查器:构建集成意味着我们不再需要在提交队列上作为单独的作业运行无效检查器,从而节省了大量的机器资源。
降低提交队列延迟:NullAway 能够显着降低提交队列延迟,因为由于 NPE 警告而导致提交队列失败变得非常罕见 ; 这个减少的延迟在我们转向
monorepo
之后变得更加显着。
使用 NullAway
图 2:在三个简单的步骤中,NullAway 确定方法m
中的表达式e
是否为空.
要了解 NullAway 的工作原理,让我们考虑一下如何确定程序中的一些表达式是否为空,这是空值检查所需要的。请考虑以下示例:
class A {
@Nullable Object f;
}
static void m(A x) {
if (x.f != null) {
System.out.println(x.f.toString());
}
}
在上面的示例中,NullAway 尝试显示x
不为空,以确保 x.f
不会导致 NPE,并且 x.f
在调用 xftoString()
时也不为null
。
对于不应该为null
的表达式,NullAway 首先尝试快速证明表达式 是非空的,例如,通过检查其类型是否不是 @Nullable
,或者是否是不能为null
的 new Object()
的表达式。
例如,由于x
的声明没有注释为 @Nullable
,所以 NullAway 可以假设它不为空,从而显示 x.f
是安全的。NullAway 通过确定 @Nullable
表达式从不作为参数传递给方法m
的方式执行这一假设。
如果快速检查失败,NullAway 试图使用数据流分析和充分利用检查框架现有的库显示非 null 的含量。数据流分析的一个主要目的是发现代码中的现有 null。
对于上面的例子中的 xftoString()
调用,快速检查不能显示 x.f
不能为 null,因为 A.f
字段是 @Nullable
。然而,我们的数据流分析使用封闭的条件检查, xf!= null
来表示 x.f.toString()
的调用是安全的。由于数据流分析可能很昂贵(它需要计算控制流图并运行定点计算),所以 NullAway 每个方法只运行一次分析,并缓存结果。
在 NullAway GitHub 页面上,有关于如何在 Android 应用程序或其他 Uber Engineering 和开源的 NullAway 上运行该工具的详细说明,NullAway 是消除 NPE 的快速实用工具,帮助其他人部署更可靠的 Android 应用程序。有关 NullAway 的详细检查,错误信息和限制的更多详细信息,请参阅我们的实施指南。
链接:
原文链接: