Java8 新特性 学习笔记(四)

optional类

我们经常会遇到这种情况:首先判断一个对象是否为null,如果不为null,获取一个对象中的一个属性,如果该属性不为null,又获取该属性的属性,如果该属性的属性不为null,又获取属性的属性的属性……
看完上面的文字有没有绕晕😵,写出来的代码也一层套一层的,很冗长

那,真的没有人去管管?当然,有🙋‍,这不,Java8 新出现了optional类

背景:

就不信你不知道的 空指针异常是导致Java应用程序失败的最常见原因。以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到Google Guava的启发,Optional类成为Java 8类库的一部分

Optional 类的引入很好的解决空指针异常👏

tip1:

Java空指针异常:

Java指针就是Java的引用,当创建一个类的对象引用,这个对象引用指向空的实体,就会产生 java.lang.NullPointException 错误

such as
(1)当一个对象不存在时又调用其方法会产生异常obj.method() // obj对象不存在
(2)当访问或修改一个对象不存在的字段时会产生异常obj.method() // method方法不存在
(3)字符串变量未初始化;
(4)接口类型的对象没有用具体的类初始化,如:List a;× / List a = new ArrayList(); √

在Java中一切都是对象,空指针就是那个没有对象的“野”孩子
那么,神奇的optional是如何让它不成为一单身汪🐕的呢

Optional实际上是个容器它可以保存类型T的值,或者仅仅保存null。它提供很多有用的方法,这样我们就不用显式进行空值检测 → 不用特意写语句判断是否为空,无敌版?

声明

import java.util.optional

它从 java.lang.Object 类中继承了很多方法,如下:
在这里插入图片描述
在这里插入图片描述
————————————————————————————————————
在optional出现前,引用的对象为空时:

public static String example(Message hua){
	if( hua == null){   //有检查是否null
		return "sorry it is null";
	}else{
		return "hello , welcome";
	}
}

optional出现后:

public static String example(Message hua){
	return Optional.ofNullable(hua).map( u -> u.xample() ).orElse("sorry it is null");
	//optional 结合 lambda表达式
}

这里看的不是很懂,没关系,但是需要知道 . > .> ,这些是Optional的链式调用,接下去一起逐一去看看optional的方法吧,👇


1.创建optional对象

Optional<String> name1 = Optional.empty(); //构造一个空的(不含值的)optional
//==如果 Optional 中的 value 为 null 则该 Optional 为不包含值的状态,然后在 API 层面将 Optional 表现的不能包含 null 值,使得 Optional 只存在 包含值 和 不包含值 两种状态

Optional<String> name2 = Optional.of(""); //对象一定不是 null !!,当把null 值作为参数传递进去,of() 方法会抛出 NullPointerException

Optional<String> name3 = Optional.ofNullable(null); //对象可能 null 可能不是 null

2.访问 / 获取 Optional对象的值:
-···- get() 、 isPresent() 、ifPresent()

//使用时直接调用方法 即可
//get()简单源码如下,都可跳过:
public T get() {
 	if (value == null) {
	   throw new NoSuchElementException("No value present");
   	}
	return value;
}

使用:

Optional<User> user1 = Optional.ofNullable(user); //⬅attention,第三类

user1.get();

//不确定时,可以先调用isPresent()
// 🐟
//if(user1.isPresent()) {
//       user1.get();
// }

//🐟🐟,或,ifPresent()通过传入一个Consumer,如果不为空,就会执行传入的Lambda 表达式
//user1.ifPresent( x-> { System.out.println(具体操作); } );
//isPresent() 源码
public boolean isPresent() {
	return value != null;
}
//ifPresent() 源码
public void ifPresent(Consumer<? super T> consumer) {
  	if (value != null)
  		consumer.accept(value);
 }

3.返回默认值
为了避免异常,Optional 的 API(应用程序接口) 提供了返回对象值,或是在为空的情况下返回默认值
orElse() 、 orElseGet() 、 orElseThrow()

//orElse() 源码
//如果包装对象值非空,返回包装对象值,否则返回入参other的值(默认值)
public T orElse(T other) {
 	 return value != null ? value : other;
}
return Optional.ofNullable(student).map( u->u.example() ).orElse("返回语句");
//orElseGet() 源码
//与orElse()类似,区别在于orElseGet()方法的入参为一个Supplier对象,用Supplier对象的get()方法的返回值作为默认值
public T orElseGet(Supplier<? extends T> other) {
 	return value != null ? value : other.get();
}
return Optional.ofNullable(student).map( u->u.example() ).orElseGet(() -> "返回语句");
//orElseThrow() 源码
//与orElseGet()方法非常相似,入参都是Supplier对象,但这里的Supplier对象必须返回一个Throwable异常,并在orElseThrow()中将异常抛出
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
	 if (value != null) {
		  return value;
	 }else{
 		 throw exceptionSupplier.get();
  	}
}
return Optional.ofNullable(student).map( u->u.example()).orElseThrow(() -> new RuntimeException("返回语句"));
//适用于包装对象值为空时 ,需要抛出特定异常的场景

4.值转换
map()、flatMap()

//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(函数式接口)对象,将Optional中的包装对象用Function函数进行运算,并包装成新的Optional对象(包装对象的类型可能改变)
public static Optional<Integer> example(Message hua){
  	return Optional.ofNullable(hua).map( u->u.example() ); 
}
//先用ofNullable()方法构造一个Optional<Message>对象,然后用map()操作,返回Optional<Integer>对象(如果hua为null, 返回map()方法返回一个空的Optinal对象)
//faltMap() 源码
//跟map()方法不同的是,入参Function函数的返回值类型为Optional<U>类型,而不是U类型,这样flatMap()能将一个二维的Optional对象映射成一个一维的对象
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():

public static Optional<Integer> example(Message hua){
        return Optional.ofNullable(hua).flatMap( u -> Optional.ofNullable( u.example() ) ); 
}

different

  • map()中获取的返回值自动被Optional包装,即 返回值 -> Optional<返回值>
    flatMap()中返回值保持不变,但必须是Optional类型,即Optional<返回值> -> Optional<返回值>

5.过滤值,用来筛选,检验参数是否符合条件
filter()

//filter() 源码
//接受参数为Predicate对象,用于对Optional对象进行过滤,如果符合Predicate的条件,返回Optional对象本身,否则返回一个空的Optional对象
Optional.ofNullable(对象).filter( u -> u.example() > 条件).ifPresent( u ->  System.out.println("The example is right."));

最后举个小实栗:

  1. 允许空值:
Optional< String > fullName = Optional.ofNullable( null );
System.out.println( "Full Name is set? " + fullName.isPresent() );
System.out.println( "Full Name: " + fullName.orElseGet( () -> "[none]" ) ); 
System.out.println( fullName.map( s -> "Hello " + s + "!" ).orElse( "byebye" ) );

输出:

Full Name is set? false
Full Name: [none]
byebye

如果Optional类的实例为非空值的话,isPresent()返回true,否从返回false。为了防止Optional为空值,orElseGet()方法通过回调函数来产生一个默认值。map()函数对当前Optional的值进行转化,然后返回一个新的Optional实例。orElse()方法和orElseGet()方法类似,但是orElse接受一个默认值而不是一个回调函数。

  1. 当对象的引用不空:
Optional< String > firstName = Optional.of( "Tony" );
System.out.println( "First Name is set? " + firstName.isPresent() );
System.out.println( "First Name: " + firstName.orElseGet( () -> "[none]" ) ); System.out.println( firstName.map( s -> "Hello " + s + "!" ).orElse( "byebye" ) );
System.out.println();

输出:

First Name is set? true
First Name: Tony
Hello Tony

but❗,当考虑情况特别少或因封装而增加代码量时,推荐用if-else。两者本质是一样的,因地制宜合理使用。

今天optional类的学习到这里结束啦,很浅,很多方法都学的一知半解的,了解地远远不够,后续看到相关内容会及时增改,如有不正之处,欢迎指正!万分感谢!🙇‍

主要学习博客:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值