参考链接:
Lists.newArrayList()和 new ArrayList () 的区别_张新玲的博客-CSDN博客_lists.newarraylist()
【Java】StringUtils的isEmpty()和isBlank()方法的使用和区别解析__陈同学_的博客-CSDN博客_stringutils.isblank和isempty
StringUtils.isEmpty()方法的使用_莺歌zzZ的博客-CSDN博客_stringutils.isempty
Java8- Optional.flatMap和Optional.map之间的区别 - 问答 - 腾讯云开发者社区-腾讯云
在开发过程中,经常会遇到NullPointerException,为了避免空指针异常,我们常常需要进行一些防御式的检查,所以在代码中常常可见if(obj != null) 这样的判断。幸好在JDK1.8中,java为我们提供了一个Optional类,Optional类能让我们省掉繁琐的非空的判断。
public final class Optional{ private static final Optional> EMPTY = new Optional<>(); private final T value; private Optional() { this.value = null; } public static Optional empty() { @SuppressWarnings("unchecked") Optional t = (Optional ) EMPTY; return t; } private Optional(T value) { this.value = Objects.requireNonNull(value); } ...... }
Optional类提供的方法主要如下:
作用:把指定的值封装成Optional对象,如果指定的值为null,则抛出空指针异常。
对应源码如下:
public staticOptional 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.(Optional.java:96) at java.util.Optional.of(Optional.java:108) at json.Test01.main(Test01.java:50)
作用:把指定的值封装为Optional对象,如果指定的值为null,则创建一个空的Optional对象。
对应源码如下:
public staticOptional ofNullable(T value) { return value == null ? empty() : of(value); }
举例说明:
// 创建一个值为null的Optional对象 Optional
输出结果:
o = Optional.empty stringOptional = Optional[小崔]
作用:创建一个空的Optional对象
对应源码如下:
public staticOptional empty() { @SuppressWarnings("unchecked") Optional t = (Optional ) EMPTY; return t; }
举例说明:
Optional
输出结果:
empty = Optional.empty
作用:如果创建的Optional中有值存在,则返回此值,否则抛出NoSuchElementException。
对应源码如下:
public T get() { if (value == null) { throw new NoSuchElementException("No value present"); } return value; }
举例说明:
Optionalo = Optional.of("小崔"); String o1 = o.get(); System.out.println("o1 = " + o1); // Optional
输出结果:
o1 = 小崔 Exception in thread "main" java.lang.NullPointerException at java.util.Objects.requireNonNull(Objects.java:203) at java.util.Optional.(Optional.java:96) at java.util.Optional.of(Optional.java:108) at json.Test01.main(Test01.java:68)
作用:如果创建的Optional中有值存在,则返回此值,否则返回一个默认值.
对应源码如下:
public T orElse(T other) { return value != null ? value : other; }
举例说明1:
OptionalstringOptional = Optional.of("小崔"); String newOptional = stringOptional.orElse("真棒"); System.out.println("newOptional = " + newOptional); Optional 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():
作用:如果创建的Optional中有值存在,则返回此值,否则返回一个由Supplier接口生成的值。
对应源码如下:
public T orElseGet(Supplier extends T> other) { return value != null ? value : other.get(); }
举例说明:
OptionalstringOptional = Optional.of("小崔"); // orElseGet与orElse方法类似,区别在于orElse传入的是默认值,而orElseGet可以接受一个lambda表达式生成默认值。 String orElseGet = stringOptional.orElseGet(() -> "真棒"); System.out.println("orElseGet = " + orElseGet); Optional emptyOptional = Optional.empty(); String orElseGet2 = emptyOptional.orElseGet(() -> "真棒"); System.out.println("orElseGet2 = " + orElseGet2);
输出结果:
orElseGet = 小崔 orElseGet2 = 真棒
作用:如果创建的Optional中有值存在,则返回此值,否则抛出一个有指定的Supplier接口生成的异常。
对应源码如下:
publicT 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) { OptionalstringOptional = Optional.of("小崔"); System.out.println(stringOptional.orElseThrow(CustomException::new)); Optional 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)
作用:如果创建的Optional中的值满足filter中的条件,则返回包含该值的Optional对象,否则返回一个空的Optional对象。
对应源码如下:
public Optionalfilter(Predicate super T> predicate) { Objects.requireNonNull(predicate); if (!isPresent()) return this; else return predicate.test(value) ? this : empty(); }
举例说明:
OptionalstringOptional1 = Optional.of(12345); System.out.println(stringOptional1.filter(e -> e % 2 == 0)); Optional stringOptional2 = Optional.of(12345); System.out.println(stringOptional2.filter(e -> e % 2 == 1)); Optional stringOptional3 = Optional.of("小崔"); System.out.println(stringOptional3.filter(e->e.length() > 5).orElse("加油")); Optional 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。
作用:如果创建的Optional中的值存在,对该值执行提供的Function函数调用。
对应源码如下:
public Optional 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对象 OptionalstringOptional = 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 真棒
作用:如果创建的Optional中的值存在,就对该值执行提供的Function函数调用,返回一个Optional类型的值,否则就返回一个空的Optional对象。
flatMap与map(Funtion)方法类似,区别在于flatMap中的mapper函数返回值必须是Optional,map方法的mapper函数返回值可以是任何类型T。调用结束时,flatMap不会对结果用Optional封装。
对应源码如下:
public Optional flatMap(Function super T, Optional> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Objects.requireNonNull(mapper.apply(value)); } }
举例说明1:
// map方法中的lambda表达式返回值可以是任意类型,在map函数返回之前会包装为Optional,但flatMap方法中的lambda表达式返回值必须是Optional实例 OptionalstringOptional = Optional.of("小崔"); System.out.println(stringOptional.flatMap(e -> Optional.of("小崔")).orElse("加油")); Optional 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,方便使用 Optionalopt = Optional .ofNullable(11) .flatMap(a -> calculate(a)); System.out.println("opt = " + opt); // 对于calculate这种函数,如果使用map,返回的结果嵌套了Optional Optional > opt2 = Optional .ofNullable(11) .map(a -> calculate(a)); System.out.println("opt2 = " + opt2); } public static Optional 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) { Optionals = 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 getOutputOpt(String input) { return input == null ? Optional.empty() : Optional.of("output for " + input); } }
作用:如果创建的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
作用:如果创建的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:小崔
public static void main(String[] args) { Listlist = 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) { Listlist = null; List newList = Optional.ofNullable(list).orElse(Lists.newArrayList()); newList.forEach(x -> System.out.println(x)); } -----------------注意-------------------- 使用Lists.newArrayList()前需要引入guava依赖: 才能导入Lists:import` `com.google.common.collect.Lists; 使用Lists.newArrayList()和new ArrayList()的区别主要在于使用Lists.newArrayList()能够自动推导泛型类型,但在JDK1.7中有了diamond操作符 <>也可推导泛型类型,例如: List com.google.guava guava 28.1-jre list = new ArrayList (); // 老版本写法 List list = new ArrayList<>(); // JDK1.7及以后的写法:省略了后面的泛型 ArrayList 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 staticOptional ofNullable(T value) { return value == null ? empty() : of(value); } public static Optional empty() { @SuppressWarnings("unchecked") Optional t = (Optional ) EMPTY; return t; } public static Optional 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依赖:
org.apache.commons commons-lang3 3.12.0
才能导入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的博客-CSDN博客。
(2)Optional.ofNullable(m1()).orElse(m2()),m1结果非空还是会执行m2!
所以,如果orElse()中的计算或其他处理业务很多时,推荐使用orElseGet():
在service层中查询一个对象,返回之后判断是否为空并做处理:
// 查询一个对象 Member member = memberService.selectByIdNo(request.getCertificateNo()); // 使用ofNullable加orElseThrow做判断和操作 Optional.ofNullable(member).orElseThrow(() -> new ServiceException("没有查询的相关数据"));