参考链接:
-
Lists.newArrayList()和 new ArrayList () 的区别_张新玲的博客-优快云博客_lists.newarraylist()
-
【Java】StringUtils的isEmpty()和isBlank()方法的使用和区别解析__陈同学_的博客-优快云博客_stringutils.isblank和isempty
-
StringUtils.isEmpty()方法的使用_莺歌zzZ的博客-优快云博客_stringutils.isempty
-
Java8- Optional.flatMap和Optional.map之间的区别 - 问答 - 腾讯云开发者社区-腾讯云
在开发过程中,经常会遇到NullPointerException,为了避免空指针异常,我们常常需要进行一些防御式的检查,所以在代码中常常可见if(obj != null) 这样的判断。幸好在JDK1.8中,java为我们提供了一个Optional类,Optional类能让我们省掉繁琐的非空的判断。
public final class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
private Optional() {
this.value = null;
}
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
......
}
Optional类提供的方法主要如下:
1. Optional.of()方法
作用:把指定的值封装成Optional对象,如果指定的值为null,则抛出空指针异常。
对应源码如下:
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
举例说明:
// 创建一个值为小崔的String类型的Optional
Optional ofOptional = Optional.of("小崔");
System.out.println("ofOptional = " + ofOptional);
// 如果我们用of方法创建Optional对象时,所传入的值为null,则抛出NullPointerException如下图所示
Optional nullOptional = Optional.of(null);
System.out.println("nullOptional = " + nullOptional);
输出结果:
ofOptional = Optional[小崔] Exception in thread "main" java.lang.NullPointerException at java.util.Objects.requireNonNull(Objects.java:203) at java.util.Optional.<init>(Optional.java:96) at java.util.Optional.of(Optional.java:108) at json.Test01.main(Test01.java:50)
2. Optional.ofNullable()方法
作用:把指定的值封装为Optional对象,如果指定的值为null,则创建一个空的Optional对象。
对应源码如下:
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
举例说明:
// 创建一个值为null的Optional对象
Optional<Object> o = Optional.ofNullable(null);
System.out.println("o = " + o);
// 创建一个值为小崔的Optional对象
Optional<String> stringOptional = Optional.ofNullable("小崔");
System.out.println("stringOptional = " + stringOptional);
输出结果:
o = Optional.empty stringOptional = Optional[小崔]
3. Optional.empty()
作用:创建一个空的Optional对象
对应源码如下:
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
举例说明:
Optional<Object> empty = Optional.empty();
System.out.println("empty = " + empty);
输出结果:
empty = Optional.empty
4. Optional.get()
作用:如果创建的Optional中有值存在,则返回此值,否则抛出NoSuchElementException。
对应源码如下:
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
举例说明:
Optional<String> o = Optional.of("小崔");
String o1 = o.get();
System.out.println("o1 = " + o1);
// Optional<Object> o2 = Optional.of(null);
// Optional<Object> o2 = Optional.ofNullable(null);
Optional<Object> o2 = Optional.empty();
Object o3 = o2.get();
System.out.println("o3 = " + o3);
输出结果:
o1 = 小崔 Exception in thread "main" java.lang.NullPointerException at java.util.Objects.requireNonNull(Objects.java:203) at java.util.Optional.<init>(Optional.java:96) at java.util.Optional.of(Optional.java:108) at json.Test01.main(Test01.java:68)
5. Optional.orElse()
作用:如果创建的Optional中有值存在,则返回此值,否则返回一个默认值.
对应源码如下:
public T orElse(T other) {
return value != null ? value : other;
}
举例说明1:
Optional<String> stringOptional = Optional.of("小崔");
String newOptional = stringOptional.orElse("真棒");
System.out.println("newOptional = " + newOptional);
Optional<Object> empty = Optional.empty();
Object orElse = empty.orElse("加油");
System.out.println("orElse = " + orElse);
输出结果:
newOptional = 小崔 orElse = 加油
需要注意的是:不论容器是否为空,只要调用该方法,则对象other一定存在。
如果调用的是方法的话,不论容器是否为空方法始终会执行,所以orElse推荐场景为设置具体值,调用具体方法使用orElseGet。
举例说明2:Optional.ofNullable(m1()).orElse(m2()),m1结果非空还是会执行m2!

所以,如果orElse()中的计算或其他处理业务很多时,推荐使用orElseGet():

6.orElseGet()
作用:如果创建的Optional中有值存在,则返回此值,否则返回一个由Supplier接口生成的值。
对应源码如下:
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
举例说明:
Optional<String> stringOptional = Optional.of("小崔");
// orElseGet与orElse方法类似,区别在于orElse传入的是默认值,而orElseGet可以接受一个lambda表达式生成默认值。
String orElseGet = stringOptional.orElseGet(() -> "真棒");
System.out.println("orElseGet = " + orElseGet);
Optional<String> emptyOptional = Optional.empty();
String orElseGet2 = emptyOptional.orElseGet(() -> "真棒");
System.out.println("orElseGet2 = " + orElseGet2);
输出结果:
orElseGet = 小崔 orElseGet2 = 真棒
7. orElseThrow()
作用:如果创建的Optional中有值存在,则返回此值,否则抛出一个有指定的Supplier接口生成的异常。
对应源码如下:
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
举例说明:
public class Test01 {
public static void main(String[] args) {
Optional<String> stringOptional = Optional.of("小崔");
System.out.println(stringOptional.orElseThrow(CustomException::new));
Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional.orElseThrow(CustomException::new));
}
private static class CustomException extends RuntimeException {
private static final long serialVersionUID = -4399699891687593264L;
public CustomException() {
super("自定义异常");
}
public CustomException(String message) {
super(message);
}
}
}
输出结果:
小崔 Exception in thread "main" json.Test01$CustomException: 自定义异常 at java.util.Optional.orElseThrow(Optional.java:290) at json.Test01.main(Test01.java:95)
8. filter()
作用:如果创建的Optional中的值满足filter中的条件,则返回包含该值的Optional对象,否则返回一个空的Optional对象。
对应源码如下:
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
举例说明:
Optional<Integer> stringOptional1 = Optional.of(12345);
System.out.println(stringOptional1.filter(e -> e % 2 == 0));
Optional<Integer> stringOptional2 = Optional.of(12345);
System.out.println(stringOptional2.filter(e -> e % 2 == 1));
Optional<String> stringOptional3 = Optional.of("小崔");
System.out.println(stringOptional3.filter(e->e.length() > 5).orElse("加油"));
Optional<String> stringOptional4 = Optional.empty();
System.out.println(stringOptional4.filter(e -> e.length() > 5).orElse("真棒"));
输出结果:
Optional.empty Optional[12345] 加油 真棒
注意:Optional中的filter方法和Stream中的filter方法是有点不一样的,Stream中的filter方法是对一堆元素进行过滤,而Optional中的filter方法只是对一个元素进行过滤,可以把Optional看成是最多只包含一个元素的Stream。
9. map()
作用:如果创建的Optional中的值存在,对该值执行提供的Function函数调用。
对应源码如下:
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
举例说明:
// map方法执行传入的lambda表达式参数对Optional实例的值进行修改,修改后的返回值仍然是一个Optional对象
Optional<String> stringOptional = Optional.of("MrCui");
System.out.println(stringOptional.map(e -> e.toUpperCase()).orElse("加油"));
stringOptional = Optional.empty();
System.out.println(stringOptional.map(e -> e.toUpperCase()).orElse("真棒"));
输出结果:
MRCUI 真棒
10. flatMap()
作用:如果创建的Optional中的值存在,就对该值执行提供的Function函数调用,返回一个Optional类型的值,否则就返回一个空的Optional对象。
flatMap与map(Funtion)方法类似,区别在于flatMap中的mapper函数返回值必须是Optional,map方法的mapper函数返回值可以是任何类型T。调用结束时,flatMap不会对结果用Optional封装。
对应源码如下:
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}
举例说明1:
// map方法中的lambda表达式返回值可以是任意类型,在map函数返回之前会包装为Optional,但flatMap方法中的lambda表达式返回值必须是Optional实例
Optional<String> stringOptional = Optional.of("小崔");
System.out.println(stringOptional.flatMap(e -> Optional.of("小崔")).orElse("加油"));
Optional<Object> objectOptional = Optional.empty();
System.out.println(objectOptional.flatMap(e -> Optional.empty()).orElse("真棒"));
输出结果:
小崔 真棒
举例说明1:
public class Test01 {
public static void main(String[] args) {
// 对于calculate这种函数,使用flatMap的话,返回的结果还是Optional,方便使用
Optional<Integer> opt = Optional
.ofNullable(11)
.flatMap(a -> calculate(a));
System.out.println("opt = " + opt);
// 对于calculate这种函数,如果使用map,返回的结果嵌套了Optional
Optional<Optional<Integer>> opt2 = Optional
.ofNullable(11)
.map(a -> calculate(a));
System.out.println("opt2 = " + opt2);
}
public static Optional<Integer> calculate(int input){
return Optional.of(input * 2);
}
}
输出结果:
opt = Optional[22] opt2 = Optional[Optional[22]]
它存在的必要性:因为在使用中存在很多返回值是Optional的函数,为了在Optional使用这些函数时,返回结果能方便使用,如上可以看出来使用flatMap,对于后续的链式编程非常方便。
举例说明2:如果函数返回所需的对象,则使用map;如果函数返回Optional,则使用flatMap。
public class Test0918 {
public static void main(String[] args) {
Optional<String> s = Optional.of("input");
System.out.println(s.map(Test0918::getOutput));
System.out.println(s.flatMap(Test0918::getOutputOpt));
}
static String getOutput(String input) {
return input == null ? null : "output for " + input;
}
static Optional<String> getOutputOpt(String input) {
return input == null ? Optional.empty() : Optional.of("output for " + input);
}
}
11. isPresent()
作用:如果创建的Optional中的值存在,返回true,否则返回false。
对应源码如下:
public boolean isPresent() {
return value != null;
}
举例说明:
Optional stringOptional = Optional.of("小崔");
System.out.println("stringOptional.isPresent() = " + stringOptional.isPresent());
Optional stringOptional2 = Optional.empty();
System.out.println("stringOptional2.isPresent() = " + stringOptional2.isPresent());
输出结果:
stringOptional.isPresent() = true stringOptional2.isPresent() = false
12. ifPresent()
作用:如果创建的Optional中的值存在,则执行该方法的调用,否则什么也不做。
对应源码如下:
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
举例说明:
Optional stringOptional = Optional.of("小崔");
stringOptional.ifPresent(e-> System.out.println("stringOptional:"+e));
Optional stringOptional2 = Optional.empty();
stringOptional2.ifPresent(e-> System.out.println("stringOptional2:"+e));
输出结果:存在时有值输出,不存在时无输出
stringOptional:小崔
13. 方法综合调用案例
13.1 案例1:集合判空
public static void main(String[] args) {
List<String> list = null;
list.forEach(x -> System.out.println(x));
}
上面例子中,如果list先前没有进行判空处理,就会报空指针异常。
Exception in thread "main" java.lang.NullPointerException at json.Test01.main(Test01.java:15)
一般的判空处理都是通过if来实现的,但是jdk1.8提供了更优雅的处理方式,解决方式如下:
public static void main(String[] args) {
List<String> list = null;
List<String> newList = Optional.ofNullable(list).orElse(Lists.newArrayList());
newList.forEach(x -> System.out.println(x));
}
-----------------注意--------------------
使用Lists.newArrayList()前需要引入guava依赖:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.1-jre</version>
</dependency>
才能导入Lists:import` `com.google.common.collect.Lists;
使用Lists.newArrayList()和new ArrayList()的区别主要在于使用Lists.newArrayList()能够自动推导泛型类型,但在JDK1.7中有了diamond操作符 <>也可推导泛型类型,例如:
List<String> list = new ArrayList<String>(); // 老版本写法
List<String> list = new ArrayList<>(); // JDK1.7及以后的写法:省略了后面的泛型
ArrayList<Object> objects = Lists.newArrayList(); // 使用Lists.newArrayList()新建ArrayList
// 对于上例中的Optional.ofNullable(list).orElse(Lists.newArrayList())可自动推导出泛型String
其中,Optional.ofNullable(list).orElse(Lists.newArrayList())的逻辑思路是:先判断list是否为空,如果不为空直接将list赋值给newList;如果list为空,就会创建一个新的空对象集合赋值给newList,这样可以使list集合永远不为空,避免了空指针异常的发生,Optional.ofNullable()源码如下:
//静态变量 empty
private static final Optional<?> EMPTY = new Optional<>();
//如果对象为空,执行empty()方法;不为空,执行of(value)方法
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(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);
}
执行逻辑如下:
-
先执行Optional.ofNullable()方法,判断泛型对象T的value是否为空,若为空,执行empty()方法;若不为空,执行of(value)方法;
-
对于empty()方法,初始化一个泛型对象为T的Optional空对象,注意此处的空对象不等同于null;
-
对于of(value)方法,将泛型对象用于Optional构造方法的参数上,返回一个有值的对象。
通过上面两步,保证了Optional对象不为null,避免了空指针异常。
通过上面的分析可总结Optional.ofNullable(..).orElse(..)的使用方法为:
结果 = Optional.ofNullable(值1).orElse(值2)
一个底层包装好的三元运算符,值1不为空时,取值1;值1为空时,取值2。
但要注意如下:
(1)不能用于字符串判空,“ ”空字符串判定为非空
String s1 = null;
String s2 = Optional.ofNullable(s1).orElse("Others");
System.out.println("s2 = " + s2);// s2 = Others
String s3 = "";
String s4 = Optional.ofNullable(s3).orElse("Others");
System.out.println("s4 = " + s4);// s4 =
boolean s1IsEmpty = StringUtils.isEmpty(s1);// import org.apache.commons.lang3.StringUtils;
System.out.println("s1IsEmpty = " + s1IsEmpty);// s1IsEmpty = true
boolean s3IsEmpty = StringUtils.isEmpty(s3);
System.out.println("s3IsEmpty = " + s3IsEmpty);// s3IsEmpty = true
补充:
list.isEmpty();// 判断集合是否为空 List自带的
CollectionUtil.isEmpty(list);// 判断集合是否为空 Hutool中的CollUtil类中方法
CollectionUtil.isNotEmpty(list);// 判断集合是否不为空 Hutool中的CollUtil类中方法
注意:使用StringUtils.isEmpty需要引入commons-lang3依赖:
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.12.0</version> </dependency>
才能导入StringUtils:import org.apache.commons.lang3.StringUtils;
org.springframework.uti包下的StringUtils的使用和org.apache.commons.lang包下StringUtils的使用参见:org.springframework.uti包下的StringUtils的使用和org.apache.commons.lang包下StringUtils的使用_MarkMooer的博客-优快云博客。
(2)Optional.ofNullable(m1()).orElse(m2()),m1结果非空还是会执行m2!

所以,如果orElse()中的计算或其他处理业务很多时,推荐使用orElseGet():

13.2 案例2:数据库查询结果判空
在service层中查询一个对象,返回之后判断是否为空并做处理:
// 查询一个对象
Member member = memberService.selectByIdNo(request.getCertificateNo());
// 使用ofNullable加orElseThrow做判断和操作
Optional.ofNullable(member).orElseThrow(() -> new ServiceException("没有查询的相关数据"));
Java 8 Optional 类详解
7178

被折叠的 条评论
为什么被折叠?



