专业编程基础技术教程

网站首页 > 基础教程 正文

一文读懂Java 8 Optional 新技能(有人说语文是一本永远读不完的微型百科全书仿写)

ccvgpt 2024-07-23 01:27:00 基础教程 14 ℃

? java.util.optional是从JDK 8开始引的类,Optional是一个包含了空值(NULL)或非空值(NOT NULL)的对象容器,用于判断方法的返回类型是否有值,Optional的好处是可以避免由于NULL带来的异常情况,如NullPointerException。一般地,如果一个方法的返回类型是Optional,则该方法应该经量避免返回NULL,对应的应该返回一个包含了NULL对象的Optional实例。

提示:本文编写时使用的是JDK 8

一文读懂Java 8 Optional 新技能(有人说语文是一本永远读不完的微型百科全书仿写)

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()的使用场景。

Tags:

最近发表
标签列表