推荐阅读(点击即可跳转阅读)

  1. 淘宝服务端高并发分布式架构演进之路

  2. IntelliJ IDEA 从入门到上瘾教程,2019图文版!

  3. 高并发场景下缓存处理的一些思路

  4. 权限设计的一些想法和思考

之前一直在某些代码中看到过使用@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(null != 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

@NonNullFieldspackage 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@NonNullFieldspackage com.nullsafety.demo.pojo;import org.springframework.lang.NonNullApi;import org.springframework.lang.NonNullFields;

加上如下注释后的效果如下: 可以在返回值的时候接受到编译期的提示。



结语

看完文章,你至少应该了解@NonNull, @Nullable, @NonNullFields, @NonNullApi四个注解和各自的作用范围以及如何设置编译期的Null-safety检查。

看完本文有收获?请转发分享给更

©著作权归作者所有:来自51CTO博客作者mob604756f6460e的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 驰骋工作流程引擎回答湖南朋友的21个问题
  2. 索引简介
  3. MySQL中的索引的引用
  4. MySQL字符类型datetime与timestamp
  5. 快递物流发货单API接口代码及功能说明
  6. 开源数据库MySQL DBA运维实战
  7. 快递100快递信息订阅推送API接口案例代码
  8. JavaScript注释及命名规范
  9. 因为我的一个低级错误,生产数据库崩溃了将近半个小时

随机推荐

  1. szq.orm.sql详细使用实例代码
  2. szq.orm.sql
  3. Elasticsearch是什么?Elasticsearch 能够
  4. 关于.net 3.5中的委托实例
  5. C#中SQL参数传入空值出错误和如何解决办
  6. 关于脚本PowerShell的设计实例
  7. devexpress TreeList递归的实例代码
  8. C# 多线程--线程池的详细介绍
  9. CTS(common type system)的实例介绍及应用
  10. 介绍一个力软敏捷开发框架