1 はじめに
実際のプロジェクトではnullチェックの判定が必要な箇所が多く、nullチェックを行わないとNullPointerExceptionが発生することがあります。
例外の処理については、前回の記事で説明しました。
実際のプロジェクトにおけるいくつかの空の判断方法を見てみましょう
通常、オブジェクトが Null かどうかを判断します。java.util で Objects.nonNull(obj) を使用するか、hutool で ObjectUtil を使用するか、直接 null != obj を使用できます。
2. リストの空判定
List のような特別なプロジェクトでは、空でないと判断されるだけではありません。List が null に等しくないことと、List.size() が 0 に等しくないことは別のことです. この 2 つをよく混同するインターン生も社内にいます. list が null に等しくない場合は、初期化されていることを意味します. , そしてそれに属するヒープメモリの断片があります. サイト, そしてサイズが 0 であることは、そこに何も入れられていないことを意味します. たとえば、それが null に等しくない場合, それは私が今ボトルを持っていることを意味します, 0 より大きいサイズは、ボトルに水を入れたことを意味します。
実際のプロジェクトでは list.isEmpty() を使って直接判断していることもわかっています. ソースコードを見てみましょう.
ボトルに水があるかどうかを判断するのと同じです(ボトルが既に存在することが前提で、存在しない場合は NullPointerException がスローされます)。
通常は list != null && list.size > 0 で判断するか、HuTool の CollUtil ツールの isEmpty を直接使用します。セット、マップなどもあります。
3.文字列のヌル判定
ボトルと水の概念はここでも使用されています. String が null の場合, equals(String) または length() を呼び出すと java.lang.NullPointerException がスローされます.
空の文字列を判断するには、いくつかの方法があります。
1. ほとんどの人が使用する方法の 1 つで、直感的で便利ですが、非効率的です。
if(a == null || a.equals(""));
2.文字列の長さを効率的に比較します。
if(a == null || a.length() == 0);
3. Java SE 6.0 が提供され始めたばかりで、効率は方法 2 と同様です。
if(a == null || a.isEmpty());
もちろん、org.apache.commons.lang.StringUtils ツールも使用できます。
StringUtils.isNotBlank(a);
* StringUtils.isNotBlank(null) = false
* StringUtils.isNotBlank("") = false
* StringUtils.isNotBlank(" ") = false
* StringUtils.isNotBlank("bob") = true
* StringUtils.isNotBlank(" bob ") = true
该工具类中还有个isNotEmpty()方法,从注释可以很明显看出二者的差别
StringUtils.isNotEmpty(a);
* StringUtils.isNotEmpty(null) = false
* StringUtils.isNotEmpty("") = false
* StringUtils.isNotEmpty(" ") = true
* StringUtils.isNotEmpty("bob") = true
* StringUtils.isNotEmpty(" bob ") = true
4、Optional
Optional的出现就是用来防止NullpointException的。常见的方法有:
- .empty():创建一个空的Optional实例
- .of(T t) : 创建一个Optional 实例,为null时报异常
- .ofNullable(T t):若t 不为null,创建Optional 实例,否则创建空实例
- isPresent() : 判断容器中是否有值
- ifPresent(Consume lambda) :容器若不为空则执行括号中的Lambda表达式
- orElse(T t) : 获取容器中的元素,若容器为空则返回括号中的默认值
- orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回s 获取的值
- orElseThrow() :如果为空,就抛出定义的异常,如果不为空返回当前对象
- map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty()
- flatMap(Function mapper):与map 类似,要求返回值必须是Optional
- T get() :获取容器中的元素,若容器为空则抛出NoSuchElement异常
先看个常见的示例:
baseInfo类中有布尔类型的属性,是空返回false,不为空取其值,需要四行。
当使用Optional时,一行搞定,非常的优雅。
4.1 Optional对象的创建
public final class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
//可以看到两个构造方格都是private 私有的
//说明 没办法在外面new出来Optional对象
private Optional() {
this.value = null;
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
//这个静态方法大致 是创建出一个包装值为空的一个对象因为没有任何参数赋值
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
//这个静态方法大致 是创建出一个包装值非空的一个对象 因为做了赋值
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
//这个静态方法大致是 如果参数value为空,则创建空对象,如果不为空,则创建有参对象
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
}
复制代码
4.2使用场景
场景1:在service层中 查询一个对象,返回之后判断是否为空并做处理
场景2:使用Optional 和函数式编程,一行搞定
5、总结
每种方法的存在必然有适用的场景,有些情况下这种链式编程,虽然代码优雅了。但是,逻辑性没那么明显,可读性有所降低,大家项目中看情况酌情使用。