JDK8新特性-Optional类
【摘要】 个人简介作者是一个来自河源的大三在校生,以下笔记都是作者自学之路的一些浅薄经验,如有错误请指正,将来会不断的完善笔记,帮助更多的Java爱好者入门。@[toc] JDK8新特性-Optional类 教程概述本教程附有非常多的例子,看完肯定能懂Optional类!看完本教程,对于Optional类的api基本的使用完全没有问题!本教程借鉴过很多其他大佬的教程,并进行总结创新,难免会有相同之处...
个人简介
作者是一个来自河源的大三在校生,以下笔记都是作者自学之路的一些浅薄经验,如有错误请指正,将来会不断的完善笔记,帮助更多的Java爱好者入门。
@[toc]
JDK8新特性-Optional类
教程概述
- 本教程附有非常多的例子,看完肯定能懂Optional类!
- 看完本教程,对于Optional类的api基本的使用完全没有问题!
- 本教程借鉴过很多其他大佬的教程,并进行总结创新,难免会有相同之处。
- 本教程会涉及一些源码。
Optional的简单介绍
- 每个程序员都会遇到的Exception其中最常见的莫过于NullPointerException异常,为了避免这个异常的发生我们常用if去判断对象是否为null再进行使用,这样就显得很乏味,于是Optional出现了。
- Optional的好处是:使用链式编程的方式更优雅的解决NullPointerException问题
简单对比两种防止空指针方式
准备环境
//准备环境
User user = new User();
user.setUsername("aaa");
UserDetail userDetail = new UserDetail();
userDetail.setIcon("icon");
userDetail.setSignature("ccccd");
user.setUserdetail(userDetail);
UserAuthority userAuthority = new UserAuthority();
userAuthority.setAuthority(2);
userDetail.setUserAuthority(userAuthority);
class User{
private String username; //用户名
private UserDetail userdetail; //用户细节
//省略getter/setter/tostring
}
class UserDetail{
private String icon;//头像
private String signature;//个性前面
private UserAuthority userAuthority; //用户权限
//省略getter/setter/tostring
}
class UserAuthority{
private int authority; //权限
//省略getter/setter/tostring
}
JDK1.8之前的普通方式
//JDK1.8之前,如果我们要查询用户权限。要这样子
if(user!=null){
if(user.getUserdetail()!=null){
if(user.getUserdetail().getUserAuthority()!=null)
{
System.out.println("JDK1.8之前查权限:"+user.getUserdetail().getUserAuthority().getAuthority());
}else {
System.out.println(333);
}
}
}
JDK1.8之后使用Optional方式
//JDK1.8之后,如果我们要查询用户权限。可以使用Optional类
Integer integer = Optional.ofNullable(user)
//还没有经过map,当前stream是:user对象
//经过了第一次map变成userdetail对象
.map(u -> u.getUserdetail())
//经过了第二次userauthority
.map(ud -> ud.getUserAuthority())
//authority
.map(a -> a.getAuthority())
//如果哪一层map出现null了,则会直接跳到下面这个orElse去执行。
.orElse(333);
System.out.println(integer);
创建Optional实例的三种方式
- 由于Optional类的构造方法全部都被private修饰,所以不能通过new关键字去创建,必须要通过以下三种方法进行创建。
private Optional() {
this.value = null;
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
- Optional类被final进行修饰,故无法对它进行继承。
public final class Optional<T> {
Optional类核心代码
}
of方法
of方法的特点:
- 不允许Optional的value为null,否则会立刻报错NullPointerException异常
of方法创建Optional实例
Optional<String> stringOptional = Optional.of("hello");
为什么of方法的值不能为null,否则就会报错?源码分析
public static <T> Optional<T> of(T value) {
return new Optional(value);
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
Objects.requireNonNull源码
public static <T> T requireNonNull(T obj) {
if (obj == null) {
throw new NullPointerException();
} else {
return obj;
}
}
ofNullable方法
- ofNullable的value可以为null,并且不会报错
ofNullable方法创建Optional实例
Optional<Object> optional = Optional.ofNullable("hello");
为什么ofNullable方法的值可以为null?源码分析
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
- 可以看出当value==null时,此时Optional的对象由empty方法创建,而empty方法的返回的Optional对象是由Optional类内部实例化的一个Optional实例,名字为EMPTY,并且是被private static final修饰。
private static final Optional<?> EMPTY = new Optional();
public static <T> Optional<T> empty() {
Optional<T> t = EMPTY;
return t;
}
- 当value!=null时,则调用of方法进行创建,虽然of方法不能为null否则会报错,但是此时的value一定不为空,所以of方法一定不会报错。故这个ofNullable方法一定不会报错。
empty方法
- empty方法的返回的Optional对象是由Optional类内部实例化的一个Optional实例,名字为EMPTY,并且是被private static final修饰
empty方法源码分析
private static final Optional<?> EMPTY = new Optional();
public static <T> Optional<T> empty() {
Optional<T> t = EMPTY;
return t;
}
isPresent方法
- 判断Optional的value是否存在,也就是是否不为null
isPresent方法的使用
//准备环境
User user = new User();
user.setUsername("aaa");
UserDetail userDetail = new UserDetail();
userDetail.setIcon("icon");
userDetail.setSignature("ccccd");
user.setUserdetail(userDetail);
UserAuthority userAuthority = new UserAuthority();
userAuthority.setAuthority(2);
userDetail.setUserAuthority(userAuthority);
Optional<User> optionalUser = Optional.ofNullable(user);
boolean present = optionalUser.isPresent();
System.out.println("Optional的value是否存在?"+present);
if(present){
System.out.println(optionalUser.get()); //此时一定不为null,present为true代表存在
}
isPresent源码分析
private final T value;
public boolean isPresent() {
return this.value != null;
}
-
Optional一旦创建,就会往value放值,isPresent方法的作用就是判断value是否不为空,也就是是否存在
-
还有就是String s="",也代表存在,而String s=null,则是不存在。
ifPresent方法
- 一定要区别于isPresent和ifPresent方法。
ifPresent方法使用
Optional<String> optionalS = Optional.ofNullable(null);
//如果Optional的value存在则会执行System.out.println("ifpresent="+s)这段代码,反之则不会执行。
optionalS.ifPresent(s->System.out.println("ifpresent="+s));
ifPresent源码分析与isPresent区别
public void ifPresent(Consumer<? super T> action) {
if (this.value != null) {
action.accept(this.value);
}
}
- ifPresent没有返回值,接收参数是lambda表达式,如果this.value不会空才会执行这个lambda表达式。
public boolean isPresent() {
return this.value != null;
}
- 而isPresent方法是不用参数的,并且返回boolean值,也是判断this.value是否存在。本质上都差不多
orElse方法
- 当optional的value为null,或者经过map映射的optional的value为null,则会执行orElse方法
- 本质上orElse方法就是当optional的value为null时的兜底方法。
Optional<String> optional1 = Optional.ofNullable("hello");
String s1 = optional1.orElse("orElse111---");
System.out.println(s1); //hello
Optional<String> optional2 = Optional.ofNullable(null);
String s2 = optional2.orElse("orElse222---");
System.out.println(s2); // orElse222---
orElse方法源码解析
public T orElse(T other) {
return this.value != null ? this.value : other;
}
意思是如果this.value如果存在,返回结果就是这个value,如果value不存在,则会返回other,other就是我们的兜底方案。
orElseGet方法
- orElse和orElseGet差不多,只是形参不同,orElseGet需要传入lambda的Supplier 表达式,格式为:()->xxx
orElseGet方法使用
Object o = Optional.ofNullable(null)
.orElseGet(() -> "orElseGet");
System.out.println(o);
orElseGet源码解析
public T orElseGet(Supplier<? extends T> supplier) {
return this.value != null ? this.value : supplier.get();
}
如果this.value存在,则返回this.value,反之则使用传过来的supplier的值
orElse和orElseGet区别
- 如果optional的value!=null,orElse方法也要执行。即使value不为null,也要执行。
- 而orElseGet方法只有value==null才会执行
- 对于orElse方法这种特性是极其浪费性能的。
private static String getName() {
System.out.println("getname");
return "张三";
}
String s1 = Optional.ofNullable("666")
.orElse(getName());
System.out.println(s1);
输出
getname
666
private static String getName() {
System.out.println("getname");
return "张三";
}
String s2 = Optional.ofNullable("777")
.orElseGet(() -> getName());
System.out.println(s2);
输出
777
orElseThrow方法
- 其实就是当value为null时,兜底方法就是抛自定义异常。
String n=null;
String s = Optional.ofNullable(n)
.orElseThrow(() -> new RuntimeException("excp"));
System.out.println(s);
输出
Exception in thread "main" java.lang.RuntimeException: excp
at com.jdk8.optional.Optional06.lambda$main$0(Optional06.java:11)
at java.base/java.util.Optional.orElseThrow(Optional.java:408)
at com.jdk8.optional.Optional06.main(Optional06.java:11)
filter方法
filter方法的使用请参照我的一篇Stream流的教程。。。
- 其实filter过滤就像是if语句,只把符合条件的筛选出来。
使用
//准备环境
User user1 = new User();
user1.setUsername("aaa");
User user2 = new User();
user2.setUsername("bbb");
User user3 = new User();
user3.setUsername("ccc");
Optional<User> optionalUser1 = Optional.ofNullable(user1)
.filter(x -> x.getUsername().equals("bbb"));
System.out.println(optionalUser1);//Optional.empty
Optional<User> optionalUser2 = Optional.ofNullable(user2)
.filter(x -> x.getUsername().equals("bbb"));//Optional[User{username='bbb', userdetail=null}]
System.out.println(optionalUser2);
输出
Optional.empty
Optional[User{username='bbb', userdetail=null}]
map方法
map方法的使用请参照我的一篇Stream流的教程。。。
- map的作用就是把一个对象进行转换,比如下面的,map的作用就是把User对象转换成UserDetail对象。
案例:传入User对象,返回UserDetail对象
//准备环境
User user = new User();
user.setUsername("aaa");
UserDetail userDetail = new UserDetail();
userDetail.setIcon("icon");
userDetail.setSignature("ccccd");
user.setUserdetail(userDetail);
UserAuthority userAuthority = new UserAuthority();
userAuthority.setAuthority(2);
userDetail.setUserAuthority(userAuthority);
//传入User对象,返回UserDetail对象
Optional<UserDetail> optionalUserDetail =
Optional
.of(user)
.map(User::getUserdetail);
System.out.println(optionalUserDetail.get());
输出
UserDetail{icon='icon', signature='ccccd', userAuthority=UserAuthority{authority=2}}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)