Spring 中的Null-Safety
之前一直在某些代码中看到过使用@Nullable 标注过的注释,当时也没有在意到底是什么意思,所以这篇文章来谈谈Spring中关于Null的那些事。
在Java中不允许让你使用类型表示其null的安全性,但Spring Framework 现在在org.sprinngframework.lang包提供以下注释,以便声明API和字段的可空性:
@Nullable: 用于指定参数、返回值或者字段可以作为null的注释。@NonNull: 与上述注释相反,表明指定参数、返回值或者字段不允许为null。(不需要@NonNullApi和@NonNullFields适用的参数/返回值和字段)@NonNullApi: 包级别的注释声明非null作为参数和返回值。@NonNullFields:包级别的注释声明字段默认非空
Spring Framework 本身利用了上面这几个注释,但它们也可以运用在任何基于Spring的Java 项目中,以声明空安全api 和 空安全字段。尚未支持泛型和数组元素的可空性,但应也即将发布在后来的版本。Spring Null-Safety出现在Spring5中,让我们更方便的编写空安全的代码,这叫做null-safety,null-safety不是让我们逃脱不安全的代码,而是在编译时产生警告。 此类警告可以在运行时防止灾难性空指针异常(NPE)。
@NonNull
@NonNull注释是null-safety的所有注释中最重要的一个,我们可以使用此注释在期望对象引用的任何地方声明非空约束:字段、方法参数或者方法返回值。
先来看一个例子
public class Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
if(name != null && name.isEmpty()){
name = null;
}
this.name = name;
}
}
上述代码对name的校验是有效的,但是存在一个缺陷,如果name被设置为null的话,那么当我们使用name的时候,就会以NullPointerException来结尾。
使用@NonNull
Spring 的null-safety特性能够允许idea或者eclipse报告这个潜在的威胁,例如,如果我们用IDEA对属性加上@NonNull会出现如下的效果。

奇怪,并没有什么变化啊,没看见有潜在的安全提示啊,那是因为你没有在idea进行设置
设置安全检查
如果你也没有提示的话,可以通过如下的方式设置安全检查

如果还不好使的话,那就在右侧 configuration annotations 添加一下 @NonNull和 @Nullable 所在的jar包,如下:

添加上,打上 ✅ 即可看到如下效果。

现在fullName 已经被@NonNull 注释添加编译器检查null值的功能了!
如果你不相信的话,可以把@NonNull 注释去掉,你的鼠标再放在fullName 上,已经没有这句提示了。
@NonNullFields
@NonNull 注解能够帮助你确保null-safety。然而,如果此注释直接装饰所有的字段的话,就会污染整个代码库。
Spring提供了另外一个不允许为null的注解 — @NonNullFields。这个注解适合用在包级别上,通知我们的开发工具注释包中所有的字段,默认的,不允许为null
新建一个Parent类,并在该类所属包下创建一个名为package-info.java的类,创建的不是Java类,而是创建的file,名为package-info.java,如下
package-info.java
@NonNullFields
package com.nullsafety.demo.pojo;
import org.springframework.lang.NonNullFields;
新建一个Parent.java 类
public class Parent {
private String son;
private String age;
private String name;
public void setSon(String son) {
if(son != null && son.isEmpty()){
son = null;
}
this.son = son;
}
public void setAge(String age) {
if(age != null && age.isEmpty()){
age = null;
}
this.age = age;
}
public void setName(String name) {
if(name != null && name.isEmpty()){
name = null;
}
this.name = name;
}
}
package-info.java 中的
@NonNullFields能够对Parent类中所有的属性起作用,把鼠标放在任意一个属性上,会出现编译期检查的提示

@Nullable
@NonNullFields注释通常比@NonNull更好,因为它有助于减少样板。 但是,有时我们想要从包级别指定的非null约束中免除某些字段,这时候就会使用到@Nullable注解
改造一下Person.java,Person.java 与pack-info.java 处于同一包下
public class Person {
@NonNull
private String fullName;
@Nullable
private String nickName;
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
if(nickName != null && nickName.isEmpty()){
nickName = null;
}
this.nickName = nickName;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
if(fullName != null && fullName.isEmpty()){
fullName = null;
}
this.fullName = fullName;
}
}
在这种情况下,我们使用@Nullable注释来覆盖字段上@NonNullFields的语义。
@NonNullApi
@NonNullFields注释仅适用于其名称所示的字段。 如果我们想对方法的参数和返回值产生相同的影响,我们需要@NonNullApi。
添加 @NonNullApi和 @NonNullFields 在 configure annotations 中,并选用NonNullApi

与@NonNullFields一样,我们需要在package-info.java 中定义@NonNullApi
package-info.java
@NonNullApi
@NonNullFields
package com.nullsafety.demo.pojo;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
加上如下注释后的效果如下: 可以在返回值的时候接受到编译期的提示。

后记:
看完文章,你至少应该了解
- 四个注解 @NonNull, @Nullable, @NonNullFields, @NonNullApi 四个注解各自的作用范围
- 如何设置编译期的Null-safety检查
欢迎关注 
Spring 中的Null-Safety的更多相关文章
- dart系列之:安全看我,dart中的安全特性null safety
目录 简介 Non-nullable类型 Nullable List Of Strings 和 List Of Nullable Strings !操作符 late关键字 总结 简介 在Dart 2. ...
- 模拟实现Spring中的注解装配
本文原创,地址为http://www.cnblogs.com/fengzheng/p/5037359.html 在Spring中,XML文件中的bean配置是实现Spring IOC的核心配置文件,在 ...
- Spring中配置数据源的4种形式
不管采用何种持久化技术,都需要定义数据源.Spring中提供了4种不同形式的数据源配置方式: spring自带的数据源(DriverManagerDataSource),DBCP数据源,C3P0数据源 ...
- spring中InitializingBean接口使用理解
InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候会执行该方法. 测试程序如下: imp ...
- Quartz 在 Spring 中如何动态配置时间--转
原文地址:http://www.iteye.com/topic/399980 在项目中有一个需求,需要灵活配置调度任务时间,并能自由启动或停止调度. 有关调度的实现我就第一就想到了Quartz这个开源 ...
- Spring中的cglib动态代理
Spring中的cglib动态代理 cglib:Code Generation library, 基于ASM(java字节码操作码)的高性能代码生成包 被许多AOP框架使用 区别于JDK动态代理,cg ...
- Spring中的JDK动态代理
Spring中的JDK动态代理 在JDK1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.在Sun刚推出动态代理时,还很难想象它有多大的实际用途,现在动态代理是实现AOP的绝好底层 ...
- 【Java EE 学习 50】【Spring学习第二天】【使用注解的DI实现】【spring中的继承】【动态代理伪hibernate实现】
一.使用注解的DI实现 1.@Resource 使用该注解能够实现引用型属性的DI实现,该注解能够根据属性名和属性类型自动给属性赋值.一般使用@Resource(name="student& ...
- Spring中文文档
前一段时间翻译了Jetty的一部分文档,感觉对阅读英文没有大的提高(*^-^*),毕竟Jetty的受众面还是比较小的,而且翻译过程中发现Jetty的文档写的不是很好,所以呢翻译的兴趣慢慢就不大了,只能 ...
随机推荐
- 51nod 1873 初中的算术【Java BigDecimal/高精度小数】
1873 初中的算术 基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题 收藏 关注 Noder现在上初三了,正在开始复习中考.他每天要计算型如 (a× a× a× ...
- 51nod 1094 和为k的连续区间【前缀和/区间差/map】
1094 和为k的连续区间 基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题 收藏 关注 一整数数列a1, a2, ... , an(有正有负),以及另一个整数k ...
- logstash filter plugin
1. 基本语法%{NUMBER:duration} %{IP:client} 2. 支持的数据类型默认会把所有的匹配都当作字符串,比如0.043, 想要转成浮点数,可以%{NUMBER:num:flo ...
- [xsy2213]tower
题意:给一个地图,地图上的每个位置是空地或一个炮或一些敌人,给定每个炮的方向(上/下/左/右),每个炮只能打一个位置且炮弹轨迹不能相交,问最多打到多少敌人 原题貌似是TC SRM 627的题,题解在这 ...
- 线程同步-CountDownLatch
应用场景: 有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行. 假如我们这个想要继续往下执行的任务调用一个CountDownLatch对象的await()方法,其他的任务执行 ...
- Android Activity为什么要细化出onCreate、onStart、onResume、onPause、onStop、onDesdroy这么多方法让应用去重载?
原文:http://www.xuebuyuan.com/1608083.html 最近在研究Activity的启动流程,老罗的blog在看,也找了其它资料学习,也跟过Android4.3的源码, 在跟 ...
- CentOS 6与CentOS 7的区别收集
说明: 1.CentOS与Ubuntu没有什么可比性,底层都是Linux,并且Ubuntu在YY广泛的使用,这些并不能说明那个强大哪个不行,只要能解决问题的都是好家伙. 2.市面上教程基本都是基于6, ...
- linux命令详解:cat命令
转:http://www.cnblogs.com/lwgdream/archive/2013/11/06/3409802.html 前言 cat命令用于读取文本文件,并且能够显示行号.特殊字符等. 使 ...
- JAVA之HashMap集合
/** * HashMap集合讲解 * HashMap集合不允许集合元素的Key重复 */package com.test; import java.util.*; public class test ...
- depth linear
float ConvertDepth( float depthFromTex, float4 cameraParams ){ const float near = cameraParams.z; co ...