首页 > 科技 >

一文读懂Java 8 Optional 新技能

2019-09-10 05:06:55 暂无 阅读:789 评论:0
一文读懂Java 8 Optional 新技能

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

相关文章