从 Java 8 引入的一个很有趣的特性是 Optional 类。Optional 类主要解决的问题是臭名昭著的空指针异常
本质上,这是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象也可以为空。
public final class Optional<T> {
/**
* Common instance for {@code empty()}.
*/
private static final Optional<?> EMPTY = new Optional<>();
/**
* If non-null, the value; if null, indicates no value is present
*/
private final T value;
/**
* Constructs an empty instance.
*
* @implNote Generally only one empty instance, {@link Optional#EMPTY},
* should exist per VM.
*/
private Optional() {
this.value = null;
}
}
通过源码分析 ,Optional是一个final类,
-
说明不能被继承
-
它的构造函数是私有的,是单列的对象
-
提供一系列的方法,对其java程序逻辑的判断和优化处理
主要方法如下:
of:为非null的值创建一个Optional。of方法通过工厂方法创建Optional类。需要注意的是,创建对象时传入的参数不能为null。如果传入参数为null,则抛出NullPointerException。因此不经常用。
ofNullable:为指定的值创建一个Optional,如果指定的值为null,则返回一个空的Optional。
isPresent:如果值存在返回true,否则返回false。
ifPresent:如果Optional实例有值则为其调用consumer,否则不做处理
get:如果Optional有值则将其返回,否则抛出NoSuchElementException。因此也不经常用。
orElse:如果有值则将其返回,否则返回指定的其它值。
orElseGet:orElseGet与orElse方法类似,区别在于得到的默认值。orElse方法将传入的字符串作为默认值,orElseGet方法可以接受Supplier接口的实现用来生成默认值
orElseThrow:如果有值则将其返回,否则抛出supplier接口创建的异常。
filter:如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional。
map:如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。
flatMap:如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional
1.of和ofNullable 初始化Optional对象
User user = userservice.getId("1");
Optional<User> optional = Optional.ofNullable(user);
Optional<User> optional1 = Optional.of(user);
两个方法的不同之处在于如果你把 null 值作为参数传递进去,of() 方法会抛出 NullPointerException:
of方法的底层有一个这个方法
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
应该明确对象不为 null 的时候使用 of()。
如果对象即可能是 null 也可能是非 null,你就应该使用 ofNullable() 方法:
2.isPresent()方法 如果为空就返回false
isPresent()方法的源码:
public boolean isPresent() {
return value != null;
}
isPresent()方法用于判断包装对象的值是否非空
User user = null;
//上面那个user相当于从数据库查询
//User user = userService.getUser(id)
Optional<User> optionalUser = Optional.ofNullable(user);
if (!optionalUser.isPresent()){
System.out.println("用户找不到");
}
//简化为
User user1 = Optional.ofNullable(user).orElseThrow(() -> new RuntimeException("用户找不到"));
user对象是null。所以optional.isPresent()
结果就是false。所以出现异常
3.orElse()方法 有值则返回该值,否则返回传递给它的参数值
orElse()方法的源码:
public T orElse(T other) {
return value != null ? value : other;
}
包装对象值非空,返回包装对象值,否则返回入参other的值
User user =null;
//可以达到赋默认值
User user2 = Optional.ofNullable(user).orElse(new User());
//这个时候user2对象不为空,只不过里面属性的值为空
User zzz = Optional.ofNullable(user2).orElse(new User(1, "zzz", "111"));
System.out.println("zzz="+zzz);
user2.setUsername(Optional.ofNullable(user2.getUsername()).orElse("liang"));
user2.setPassword(Optional.ofNullable(user2.getPassword()).orElse("123456"));
System.out.println("user2="+user2);
//输出结果
zzz=User{id=null, username=null, password=null}
user2=User{id=null, username='liang', password='123456'}
如上面例子,当user对象为空时,就会new一个对象赋值给user2,当user2不为空时,拿的还是user2的原先的值(new User() )赋值给zzz。
4.orElseGet()方法 在有值的时候返回值,如果没有值,它会执行作为参数传入的 Supplier(供应者) 函数式接口,并将返回其执行结果
orElseGet()方法的源码:
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
orElseGet()方法与orElse()方法类似,区别在于orElseGet()方法的入参为一个Supplier对象,用Supplier对象的get()方法的返回值作为默认值。
User user3 = Optional.ofNullable(user).orElseGet(() -> {
//可以加各种处理逻辑
User user1 = new User();
user1.setUsername("zhangsan");
return user1;
});
5.orElseGet()方法 与orElse()方法 的区别
乍一看,这两种方法似乎起着同样的作用。然而事实并非如此。我们创建一些示例来突出二者行为上的异同。
先看对象不为空的情况
public static void main(String[] args){
List<Integer> list = Arrays.asList(23,1,3);
int myElse = list.stream().reduce(Integer::sum).orElse(get("myElse"));
int myElseGet = list.stream().reduce(Integer::sum).orElseGet(() -> get("myElseGet"));
System.out.println("myElse的值"+myElse);
System.out.println("myElseGet的值"+myElseGet);
}
public static int get(String name){
System.out.println(name+"执行了该方法");
return 1;
}
//输出结果
myElse执行了该方法
myElse的值27
myElseGet的值27
对象为空的情况
public static void main(String[] args){
List<Integer> list = Arrays.asList();
int myElse = list.stream().reduce(Integer::sum).orElse(get("myElse"));
int myElseGet = list.stream().reduce(Integer::sum).orElseGet(() -> get("myElseGet"));
System.out.println("myElse的值"+myElse);
System.out.println("myElseGet的值"+myElseGet);
}
public static int get(String name){
System.out.println(name+"执行了该方法");
return 1;
}
从上面optional为空值和有值的情况的例子可以看到orElse在不论optional有没有值的时候都会执行,在optional为空值的情况下orElse和orElseGet都会执行,当optional不为空时,orElseGet不会执行。
6.orElseThrow 它会在对象为空的时候抛出异常,而不是返回备选的值
orElseThrow()方法的源码:
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
orElseThrow()方法其实与orElseGet()方法非常相似了,入参都是Supplier对象,只不过orElseThrow()的Supplier对象必须返回一个Throwable异常,并在orElseThrow()中将异常抛出:
User user1 = Optional.ofNullable(user).orElseThrow(() -> new RuntimeException("用户找不到"));
如果user为null,就会抛出异常。这个方法让我们有更丰富的语义,可以决定抛出什么样的异常,而不总是抛出 NullPointerException。
7.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()方法的参数为Function(函数式接口)对象,map()方法将Optional中的包装对象用Function函数进行运算,并包装成新的Optional对象(包装对象的类型可能改变)。举例如下:
public static Optional<Integer> getAge(Student student){
return Optional.ofNullable(student).map(u -> u.getAge());
}
上述代码中,先用ofNullable()方法构造一个Optional<Student>对象,然后用map()计算学生的年龄,返回Optional<Integer>对象(如果student为null, 返回map()方法返回一个空的Optinal对象)。
8.flatMap
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()方法不同的是,入参Function函数的返回值类型为Optional<U>类型,而不是U类型,这样flatMap()能将一个二维的Optional对象映射成一个一维的对象。以map方法中示例功能为例,进行faltMap()改写如下:
public static Optional<Integer> getAge(Student student){
return Optional.ofNullable(student).flatMap(u -> Optional.ofNullable(u.getAge()));
}
map和flatMap示例
User user = new User(1,"zhang_san","123456");
Optional<String> username = Optional
.ofNullable(user)
.map(user1 -> user1.getUsername())
.map(new Function<String, String>() {
@Override
public String apply(String s) {
System.out.println("s=="+s);
s = s + "你好啊";
return s;
}
})
;
System.out.println("Username is: " + username.orElse("Unknown"));
//输出结果
s==zhang_san
Username is: zhang_san你好啊
map他会把值传到下一个map对值进行处理,可以多次进行处理
Optional<String> username = Optional
.ofNullable(getUserById(id))
.map(user -> user.getUsername())
.map(name -> name.toLowerCase())
.map(name -> name.replace('_', ' '));
System.out.println("Username is: " + username.orElse("Unknown"));
flatmap:
Optional<String> username = Optional
.ofNullable(getUserById(id))
.flatMap(user -> Optional.of(user.getUsername()))
.flatMap(name -> Optional.of(name.toLowerCase()));
System.out.println("Username is: " + username.orElse("Unknown"));
9. filter()方法
filter()方法的源码:
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
filter()方法接受参数为Predicate对象,用于对Optional对象进行过滤,如果符合Predicate的条件,返回Optional对象本身,否则返回一个空的Optional对象。举例如下
public static void filterAge(Student student){
Optional.ofNullable(student).filter( u -> u.getAge() > 18).ifPresent(u -> System.out.println("The student age is more than 18."));
}
参考:https://www.jianshu.com/p/790f7c185d3e
https://www.oschina.net/translate/understanding-accepting-and-leveraging-optional-in
https://www.jianshu.com/p/d81a5f7c9c4e