? java.util.optional是从JDK 8开始引的类,Optional是一个包含了空值(NULL)或非空值(NOT NULL)的对象容器,用于判断方法的返回类型是否有值,Optional的好处是可以避免由于NULL带来的异常情况,如NullPointerException。一般地,如果一个方法的返回类型是Optional,则该方法应该经量避免返回NULL,对应的应该返回一个包含了NULL对象的Optional实例。
提示:本文编写时使用的是JDK 8
Optional源码分析
Optional是一个对象容器,你可以在java.util包中找到该类。接下来,将分析Optional类中的构造器,属性和方法。Optional类的源码和分析如下:
public final class Optional<T> { /** * EMPTY代表NULL值的Optional对象实例 */ private static final Optional<?> EMPTY = new Optional<>(); /** * 泛型类型的对象实例 */ private final T value; /** * 私有的Optional空构造函数 */ private Optional() { this.value = null; } /** * 返回内部的EMPTY实例 */ public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; } /** * 通过value实例化Optional对象,如果value为空,则抛出空指针异常 */ private Optional(T value) { this.value = Objects.requireNonNull(value); } /** * 通过value实例化Optional对象,如果value为空,则抛出空指针异常 */ public static <T> Optional<T> of(T value) { return new Optional<>(value); } /** * 通过value实例化Optional对象,如果value为空,则返回EMPTY, * 如果value不为空,则调用Optional::of(value)方法 */ public static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value); } /** * 如果value的值不为空,则返回value,否则抛出NoSuchElementException异常 */ public T get() { if (value == null) { throw new NoSuchElementException("No value present"); } return value; } /** * 如果value的值不为空,返回true,否则返回false */ public boolean isPresent() { return value != null; } /** * 如果value不为NULL,则使用value调用消费者函数式接口的消费方法Consumer::accept() */ public void ifPresent(Consumer<? super T> consumer) { if (value != null) consumer.accept(value); } /** * 如果存在值,并且值与给定谓词匹配,则返回描述该值的值,否则返回空值 */ public Optional<T> filter(Predicate<? super T> predicate) { Objects.requireNonNull(predicate); if (!isPresent()) return this; else return predicate.test(value) ? this : empty(); } /** * 如果存在值,则将提供的映射函数应用于该值,如果结果为非null,则返回描述结果的值。 否则返回空 */ 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)); } } /** * 如果存在则返回值,否则返回其他给定的值 */ public T orElse(T other) { return value != null ? value : other; } /** *如果值存在,则返回该值,否则返回指定的被调用函数的返回值。 */ public T orElseGet(Supplier<? extends T> other) { return value != null ? value : other.get(); } /** * 如果值存在,则返回该值,否则抛出创建者提供的异常信息 */ public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { if (value != null) { return value; } else { throw exceptionSupplier.get(); } } // other code.... }
empty()方法
public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; }
如果明确表示一个持有NULL值的Optional实例,则使用Optional.empty()方法,例如:
Optional nullOpt = Optional.empty();
of()方法
public static <T> Optional<T> of(T value) { return new Optional<>(value); }
如果能够明确判断一个对象的值不为NULL时,应该使用Optional.of()方法,例如:
User user = userService.findById(userId); if(user != null){ Optional userOptional = Optional.of(user); }
ofNullable()方法
public static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value); }
如果无法确认一个对象的值是否为空的时候,应该使用Optional.ofNullable()方法,例如:
User user = userService.findByEmail(userEmail); Optional userOptional = Optional.ofNullable(user);
get()方法
@NotNull public T get() { if (value == null) { throw new NoSuchElementException("No value present"); } return value; }
一般地,get()方法需要先确认value的值不为空后才使用,get()方法需要先校验value存在与否。例如:
User user = userService.findByUsername(username); if(user != null){ Optional userOptional = Optional.of(user); User value = userOptional.get(); }
isPresent()方法
public boolean isPresent() { return value != null; }
isPresent()方法用于判断value是否存在,如果存在,返回true;如果不存在,返回false。例如:
User user = userService.findById(userId); boolean exist = Optional.ofNullable(user).isPresent(); Optional<User> uop = userService.findOne(userId); if(uop.isPresent()){ return uop.get(); }else{ return new User(); }
ifPresent()方法
public void ifPresent(Consumer<? super T> consumer) { if (value != null) consumer.accept(value); }
顾名思义,如果value的值不为空,则使用value调用消费者函数式接口的消费方法Consumer.accept(),例如:
User user = userService.findById(userId); Optional op = Optional.ofNullable(user); op.ifPresent(u->System.out::println);
filter()方法
public Optional<T> filter(Predicate<? super T> predicate) { Objects.requireNonNull(predicate); if (!isPresent()) return this; else return predicate.test(value) ? this : empty(); }
filter()方法用于实现简单的过滤功能,如果Optional容器包含的值不为空,则返回满足过滤条件的值,否则返回empty()函数的返回值。例如:
List<User> list = userService.findAll(); list.forEach(item->{ Optional.ofNullable(item) .filter(user-> user.getStatus == 1) .isPresent(user->System.out::println); });
map()方法
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()方法用于类型转换操作,通过功能函数mapper.apply()对value进行类型映射,重新封装为可空的Optional对象实例,例如:
List<String> list = Arrays.asList("java","jvm","jre","jdk"); Optional<List<String>> listOptional = Optional.of(list); int size = listOptional.map(List::size).orElse(0); System.out.println("size = " + size);
output:
size = 4
flatMap()方法
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)); } }
与map()方法一样,flatMap()方法也是进行类型映射操作,唯一不同于map()方法的是flatMap()方法中Optional类型返回值直接由外部决定,不需要通过值重新封装为Optional实例。例如:
public class User{ private String username; public Optional<String> getUsername(){ return Optional.ofNullable(username); } public User(String username){ this.username = username; } } public class TestFlatMapMethod{ public static void main(String[] args){ User user = new User("ramostear"); Optional<User> userOptional = Optional.of(user); Optional<Optional<String>> usernameOptional = userOptional.map(User::getUsername); //map()方法需要再次封装Optional类型 Optioanl<String> nameOptional = usernameOptional.orElseThrow(IllegalArgumentException::new); String name = nameOptional.orElse(""); System.out.println(name); //flatMap()方法不需要再次封装Optional类型 String username = userOptional.flatMap(User::getUsername).orElse(""); System.out.println(username); } }
orElse()方法
public T orElse(T other) { return value != null ? value : other; }
orElse()方法的作用是:当value的值不存在时,提供一个默认的值,例如:
String val1 = null; String val2 = "default value"; String value = Optional.ofNullable(val1).orElse(val2); String value2 = Optional.ofNullable(null).orElse("default value");
orElseGet()方法
public T orElseGet(Supplier<? extends T> other) { return value != null ? value : other.get(); }
orElseGet()方法是orElse()方法的升级版本,其好处是可以防止orElse()方法传入NULL值,例如:
String val1 = null; Supplier<String> fun = ()->"default value"; String value = Optional.ofNullable(val1).orElseGet(fun);
orElseThrow()方法
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { if (value != null) { return value; } else { throw exceptionSupplier.get(); } }
orElseThrow()方法相当于是orElse()方法和orElseGet()方法的增强版,提供了异常处理能力。需要注意的是,orElseThrow()方法处理异常时是抛出而不是捕获。例如:
String username = null; String name = Optional.ofNullable(username).orElseThrow(IllegalArgumentException::new);
orElse()与orElseGet()的区别
对于不太熟悉Optional的程序员来说,orElse()方法和orElseGet()方法之间的区别并不明显,甚至会觉得这两个方法在功能上是重叠的。然而,这两个方法还是有着本质上的区别,如果不能很好的理解其中的差异,使用这两个方法会严重影响到代码的运行性能。接下来,我们先看一个简单的例子:
public class OptionalExample { public static void main(String[] args) { String text = null;//"Hello Optional"; System.out.println("Using Optional.orElseGet() method..."); String value = Optional.ofNullable(text).orElseGet(OptionalExample::defaultValue); System.out.println("orElseGet() method return value = " + value); System.out.println("Using Optional.orElse() method..."); value = Optional.ofNullable(text).orElse(defaultValue()); System.out.println("orElse() method return value = " + value); } public static String defaultValue(){ System.out.println("Getting Default Value..."); return "Default Value"; } }
defaultValue()方法用于返回默认的值,该方法不带任何请求参数。变量text一开始的值为NULL,运行main方法并观察控制台输出:
"C:\Program Files\Java\jdk1.8.0_66\bin\java.exe"... Using Optional.orElseGet() method... Getting Default Value... orElseGet() method return value = Default Value Using Optional.orElse() method... Getting Default Value... orElse() method return value = Default Value
在变量text为NULL的情况下,orElse()方法和orElseGet()方法具有同等的作用,没有任何区别。接下来,将变量text的值修改为“Hello Optional”,运行main方法并观察控制台输出:
"C:\Program Files\Java\jdk1.8.0_66\bin\java.exe"... Using Optional.orElseGet() method... orElseGet() method return value = Hello Optional Using Optional.orElse() method... Getting Default Value... orElse() method return value = Hello Optional
当变量text有值的情况下,结果发生了改变。使用orElseGet()方法来判断text的值时,defaultValue()方法不会被执行,因为text值不为空,但使用orElse()方法来判断text值时,无论text的值是否为空,defaultValue()方法都会被执行,在这种情况下,defaultValue()方法就显得非常的冗余且影响代码性能。
为什么为产生这样的区别?原因在于orElse()方法需要提供一个类型变量,在orElse()方法工作之前,就需要确定类型变量的值,这也就是为什么在变量text有值的情况下defaultValue()方法依然被执行的原因;而orElseGet()方法的入参是对象的提供者(Supplier),只有当变量text为空的时候,才会调用对象提供者所提供的具体方法。
总结
本文详细介绍了Java 8 Optional类的基本用法、注意事项以及区别。其中值得注意的是of(),ofNullable()之间的区别,get()的使用条件,map()和flatMap()的区别,orElse和orElseGet()的使用场景。