optional详解

public class Test {

  public static void main(String[] args) {
    People people = new People();
    Optional<People> p = Optional.ofNullable(people);
    String name = p.flatMap(People::getCar).flatMap(Car::getInsurence).map(Insurence::getName).orElse("string");
  }

}

class People{
  private Optional<Car> car;

  public Optional<Car> getCar() {
    return car;
  }
}

class Car{
  private Optional<Insurence> insurence;

  public Optional<Insurence> getInsurence() {
    return insurence;
  }
}

class Insurence{
  String name;
  public String getName() {
    return name;
  }
}

 

1.Optional简述 

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


Optional:按照字面英文解释为“可选的” 意思,但此处的语义是指某个值可能有也可能没有(null)

Optional 被定义为一个简单的容器,其值可能是null或者不是null。在Java 8之前一般某个函数应该返回非空对象但是偶尔却可能返回了null,而在Java 8 以后,不推荐你返回null而是返回Optional。

 

Optional英文文档地址:http://docs.oracle.com/javase/8/docs/api/java/util/Optional.html

 

2.对 Optional 应用的理解

Java 8借鉴了Scala和Haskell,提供了一个新的Optional模板,可以用它来封装可能为空的引用。但它绝不是终结空指针,更多只是使API的设计者可以在代码层面声明一个方法可能会返回空值,调用方应该注意这种情况。因此,这只对新的API有效,前提是调用者不要让引用逃逸出封装类,否则引用可能会在外面被不安全的废弃掉。

个人对这个新的特性是又爱又恨。一方面,空指针是一个大问题,只要能解决这个问题的东西笔者都欢迎。但另一方面,个人对它是否能担此重任执怀疑的态度。这是由于使用它需要全公司的集体努力,短期内很难会有见效。若非大力地推广使用,很可能会功亏一篑。

 

3.Optional的优点

1)显式的提醒你需要关注null的情况,对程序员是一种字面上的约束
2)将平时的一些显式的防御性检测给标准化了,并提供一些可串联操作

3)解决null会导致疑惑的概念

eg:Map里面的key==null的情况,以及value==null的情况

 

4.Optional类

 

4.1 Optional类的官方描述

 

 

A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.

 

(这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。)

 

4.2 Optional的简单使用

 

Optional类的包名:java.util.Optional<T>

 

为了防止抛出java.lang.NullPointerException 异常,我们经常会写出这样的代码:

 

[java]  view plain  copy

 

  1. Student student = person.find("Lucy");  
  2.         if (student != null) {  
  3.             student.doSomething();  
  4.         }  

使用Optional的代码写法:

 

 

[java]  view plain  copy

 

  1. Student student = person.find("Lucy");  
  2.         if (student.isPresent()) {  
  3.             student.get().doSomething();  
  4.         }  
说明:如果isPresent()返回false,说明这是个空对象;否则,我们就可以把其中的内容取出来做相应的操作了。
单从代码量上来说,Optional的代码量并未减少,甚至比原来的代码还多。但好在,你绝对不会忘记判空,因为这里我们得到的不是Student类的对象,而是Optional。

 

 

4.3Optional类的主要方法

1) of(T value)

为非null的值创建一个Optional。

of()方法通过工厂方法创建Optional类。需要注意,创建对象时传入的参数不能为null。如果传入参数为null,则抛出NullPointerException 。

eg:

 

[java]  view plain  copy

 

  1. //调用工厂方法创建Optional实例  
  2.     Optional<String> myValue = Optional.of("OptionalTest");  
  3.     //传入参数为null,抛出NullPointerException.  
  4.     Optional<String> someNull = Optional.of(null);  

 

 

2) ofNullable(T value)

为指定的值创建一个Optional,如果指定的值为null,则返回一个空的Optional。

ofNullable与of方法相似,唯一的区别是可以接受参数为null的情况。

eg:

 

[java]  view plain  copy

 

  1. //下面创建了一个不包含任何值的Optional实例  
  2. //eg:值为'null'  
  3. Optional empty = Optional.ofNullable(null);  

 

 

3) isPresent()

如果值存在返回true,否则返回false。

eg:

 

[java]  view plain  copy

 

  1. //isPresent()方法用来检查Optional实例中是否包含值  
  2. if (myValue.isPresent()) {  
  3. //在Optional实例内调用get()返回已存在的值  
  4. System.out.println(myValue.get());//输出OptionalTest }  
 

 

4) get()

如果Optional有值则将其返回,否则抛出异常 NoSuchElementException。

在上面的示例中,get方法用来得到Optional实例中的值。下面是一个抛出NoSuchElementException的示例:

eg:

 

[java]  view plain  copy

 

  1. //执行下面的代码会输出:No value present   
  2.         try {  
  3.           //在空的Optional实例上调用get(),抛出NoSuchElementException  
  4.           System.out.println(empty.get());  
  5.         } catch (NoSuchElementException ex) {  
  6.           System.out.println(ex.getMessage());  
  7.         }  
 

 

5) ifPresent(Consumer<? super T> consumer)

如果Optional实例有值则为其调用consumer,否则不做处理。

要理解ifPresent()方法,首先需要了解Consumer类。简单地说,Consumer类包含一个抽象方法。该抽象方法对传入的值进行处理,但没有返回值。Java8支持不用接口直接通过lambda表达式传入参数。

如果Optional实例有值,调用ifPresent()可以接受接口段或lambda表达式。

eg:

 

[java]  view plain  copy

 

  1. //ifPresent()方法接受lambda表达式作为参数。  
  2.         //lambda表达式对Optional的值调用consumer进行处理。  
  3.         myValue.ifPresent((value) -> {  
  4.           System.out.println("The length of the value is: " + value.length());  
  5.         });  

 

 

6) orElse(T other)

如果有值则将其返回,否则返回指定的其它值。
如果Optional实例有值则将其返回,否则返回orElse方法传入的参数。即:参数other为默认返回值

eg:

 

[java]  view plain  copy

 

  1. //如果值不为null,orElse方法返回Optional实例的值。  
  2.         //如果为null,返回传入的消息。  
  3.         //输出:There is no value present!  
  4.         System.out.println(empty.orElse("There is no value present!"));  
  5.         //输出:OptionalTest  
  6.         System.out.println(myValue.orElse("There is some value!"));  

 

 

7) orElseGet(Supplier<? extends T> other)

orElseGet与orElse方法类似,区别在于得到的默认值。orElse方法将传入的参数字符串作为默认值,orElseGet方法可以接受Supplier接口的实现用来生成默认值。

eg:

 

[java]  view plain  copy

 

  1. //orElseGet可以接受一个lambda表达式生成默认值。  
  2.         //输出:Default Value  
  3.         System.out.println(empty.orElseGet(() -> "Default Value"));  
  4.         //输出:OptionalTest  
  5.         System.out.println(myValue.orElseGet(() -> "Default Value"));  

 

 

8) orElseThrow(Supplier<? extends X> exceptionSupplier)

如果有值则将其返回,否则抛出supplier接口创建的异常。
在orElseGet()方法中,我们传入一个Supplier接口。然而,在orElseThrow中我们可以传入一个lambda表达式或方法,如果值不存在就抛出异常。

eg:

 

[java]  view plain  copy

 

  1. try {  
  2.           //orElseThrow与orElse方法类似。与返回默认值不同,  
  3.           //orElseThrow会抛出lambda表达式或方法生成的异常   
  4.            
  5.           empty.orElseThrow(ValueAbsentException::new);  
  6.         } catch (Throwable ex) {  
  7.           //输出: No value present in the Optional instance  
  8.           System.out.println(ex.getMessage());  
  9.         }  

 

[java]  view plain  copy

 

  1. class ValueAbsentException extends Throwable {  
  2.    
  3.   public ValueAbsentException() {  
  4.     super();  
  5.   }  
  6.    
  7.   public ValueAbsentException(String msg) {  
  8.     super(msg);  
  9.   }  
  10.    
  11.   @Override  
  12.   public String getMessage() {  
  13.     return "No value present in the Optional instance";  
  14.   }  
  15. }  
 

 

 

9) map(Function<? super T,? extends U> mapper)

如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。
map方法用来对Optional实例的值执行一系列操作。通过一组实现了Function接口的lambda表达式传入操作。

eg:

 

[java]  view plain  copy

 

  1. //map方法执行传入的lambda表达式参数对Optional实例的值进行修改。  
  2. //为Lambda表达式的返回值创建新的Optional实例作为map方法的返回值。  
  3. Optional<String> upperName = myValue.map((value) -> value.toUpperCase());  
  4. System.out.println(upperName.orElse("No value found"));  
 

 

10) flatMap(Function<? super T,Optional<U>> mapper)

如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional。flatMap与map(Funtion)方法类似,区别在于flatMap中的mapper返回值必须是Optional。调用结束时,flatMap不会对结果用Optional封装。

flatMap方法与map方法类似,区别在于mapping函数的返回值不同。map方法的mapping函数返回值可以是任何类型T,而flatMap方法的mapping函数必须是Optional。

eg:

下面参照map函数,使用flatMap重写的示例

 

[java]  view plain  copy

 

  1. //map方法中的lambda表达式返回值可以是任意类型,在map函数返回之前会包装为Optional。   
  2. //但flatMap方法中的lambda表达式返回值必须是Optionl实例。   
  3. upperName = myValue.flatMap((value) -> Optional.of(value.toUpperCase()));  
  4. System.out.println(upperName.orElse("No value found"));  
 

 

11) filter(Predicate<? super T> predicate)

如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional。


filter个方法通过传入限定条件对Optional实例的值进行过滤。

对于filter函数我们可以传入实现了Predicate接口的lambda表达式。

eg:

 

[java]  view plain  copy

 

  1. //filter方法检查给定的Option值是否满足某些条件。  
  2.     //如果满足则返回同一个Option实例,否则返回空Optional。  
  3.     Optional<String> longName = myValue.filter((value) -> value.length() > 6);  
  4.     System.out.println(longName.orElse("The name is less than 6 characters"));//输出OptionalTest  
  5.        
  6.     //另一个例子是Optional值不满足filter指定的条件。  
  7.     Optional<String> anotherName = Optional.of("Test");  
  8.     Optional<String> shortName = anotherName.filter((value) -> value.length() > 6);  
  9.     //输出:name长度不足6字符  
  10.     System.out.println(shortName.orElse("The name is less than 6 characters"));  
 

 

12) empty()

返回一个空Optional实例。

eg:

 

[java]  view plain  copy

 

  1. Optional.<String>empty(); // 返回一个空Optional<String>  

 

 

Note:

Optional有这么多方法,那Optional的初衷是什么?而且Optional也是一个对象,所以它本身也有可能是null,这可如何是好。所以,个人认为,Optional比较适用的地方是作为返回值,这样可以给使用者一个善意的提醒。

 

4.4  map 与 flatMap 的区别

 

map(mapper) 与 flatMap(mapper) 功能上基本是一样的,只是最后的返回值不一样。map(mapper)方法中的mapper可以返回任意类型,但是flatMap(mapper)方法中的mapper只能返回Optional类型。

如果mapper返回结果result的不是null,那么map就会返回一个Optional,但是 flatMap不会对result进行任何包装。

eg:

 

[java]  view plain  copy

 

  1. Optional<String> o;  
  2. o.map((value)->Optional.of(value)) //返回的类型是Optional<Optional<String>>  
  3. o.flatMap((value)->Optional.of(value)) //返回的类型是Optional<String>  
 

 

4.5 Optional应用示例:

Note:测试的时候最好是新建一个java项目(或者直接用eclipse测试),因为Android项目目前不完全支持java8的新特性,需要配置很多东西,也一样容易出现各种问题。

 

[java]  view plain  copy

 

  1. import java.util.NoSuchElementException;  
  2. import java.util.Optional;  
  3.   
  4. public class OptionalTest {  
  5.   
  6.     public static void main(String[] args) {  
  7.          // 创建Optional  
  8.         String mayBeNull = null;  
  9.         Optional<String> opt1 = Optional.of(" Hello! ");  
  10.         Optional<String> opt2 = Optional.ofNullable(mayBeNull);  
  11.         Optional<String> opt3 = Optional.empty();  
  12.         opt1.ifPresent(System.out::println); // " Hello! "  
  13.         opt2.ifPresent(System.out::println);  
  14.         opt3.ifPresent(System.out::println);  
  15.   
  16.         //方法测试示例  
  17.         ofTest();  
  18.         ofNullableTest();  
  19.         isPresentTest();  
  20.         ifPresentTest();  
  21.         orElseTest();  
  22.         orElseGetTest();  
  23.         mapTest();  
  24.         flatMapTest();  
  25.         filterTest();  
  26.   
  27.     }  
  28.       
  29.     /** 
  30.      * of后面接给optional设置的值 但是不能为空 如果为空会报空指针异常 
  31.      */  
  32.     public static void ofTest() {  
  33.         Optional<String> optional = Optional.of("123");  
  34.         System.out.println(optional.get());  
  35.         try {  
  36.             optional = Optional.of(null);  
  37.             System.out.println("null值--"+optional.get());  //get方法是获取optional的值 类型取决于声明的时候  
  38.         } catch (NullPointerException e) {  
  39.             System.out.println("空指针异常");  
  40.         }  
  41.     }  
  42.   
  43.     /** 
  44.      * ofNullable 和of类似 但是ofNullable可以设置null值  如果是Null值得话取值会报NoSuchElementException 异常 
  45.      */  
  46.     public static void ofNullableTest() {  
  47.         Optional<String> optional = Optional.ofNullable("123");  
  48.         System.out.println(optional.get());  
  49.         try {  
  50.             optional = Optional.ofNullable(null);  
  51.             System.out.println("null值---"+optional.get());  
  52.         } catch (NoSuchElementException e) {  
  53.             System.out.println("NoSuchElementException 异常");  
  54.         }  
  55.     }  
  56.   
  57.     /** 
  58.      * ifPresent用来判断optional中有没有值存在 如果有则为真 
  59.      */  
  60.     public static void isPresentTest() {  
  61.         Optional<String> optional = Optional.ofNullable(null);  
  62.         if (optional.isPresent()) {  
  63.             System.out.println(optional.get());  
  64.         } else {  
  65.             System.out.println("值为空");  
  66.         }  
  67.     }  
  68.   
  69.     /** 
  70.      * ifPresent和isPresent类似 只不过它支持λ表达式 
  71.      */  
  72.     public static void ifPresentTest() {  
  73.         Optional<String> optional = Optional.ofNullable("123");  
  74.         optional.ifPresent(var -> {  
  75.             System.out.println(var);  
  76.         });  
  77.     }  
  78.   
  79.     /** 
  80.      * orElse方法,如果值为空的话会用参数中的值去替换 即设置默认值 
  81.      */  
  82.     public static void orElseTest() {  
  83.         Optional<String> optional = Optional.ofNullable("123");  
  84.         System.out.println(optional.orElse("有没有"));  
  85.         optional = Optional.ofNullable(null);  
  86.         System.out.println(optional.orElse("有没有000"));  
  87.     }  
  88.   
  89.     /** 
  90.      * orElseGet方法 和orElse类似 不过此方法接受Supplier接口的实现用来生成默认值 
  91.      */  
  92.     public static void orElseGetTest() {  
  93.         Optional<String> optional = Optional.ofNullable("123");  
  94.         System.out.println(optional.orElseGet(() -> "123456"));  
  95.         optional = Optional.ofNullable(null);  
  96.         System.out.println(optional.orElseGet(() -> "1234567"));  
  97.     }  
  98.   
  99.     /** 
  100.      * map方法  如果有值则会对值进行mapping中的处理 处理结果存在则创建并返回Optional类型的结果 否则返回空 
  101.      */  
  102.     public static void mapTest() {  
  103.         Optional<String> optional = Optional.ofNullable("abc");  
  104.         System.out.println(optional.map(var -> var.toUpperCase()).get());  
  105.     }  
  106.   
  107.     /** 
  108.      * flatMap和map类似 只不过mapping中必须返回Option类型的数据 
  109.      */  
  110.     public static void flatMapTest() {  
  111.         Optional<String> optional = Optional.ofNullable("abc");  
  112.         System.out.println(optional.flatMap(var -> Optional.of(var.toUpperCase())).get());  
  113.     }  
  114.   
  115.     /** 
  116.      * filter对optional进行过滤,mapping中为过滤的条件  如果不满足条件 返回一个为空的Optional 
  117.      */  
  118.     public static void filterTest() {  
  119.         try {  
  120.             Optional<String> optional = Optional.ofNullable("一二三四五六七八");  
  121.             System.out.println(optional.filter(var -> var.length() > 6).get());  
  122.             System.out.println(optional.filter(var -> var.length() < 6).get());  
  123.         } catch (NoSuchElementException e) {  
  124.             System.out.println("optional的值为空");  
  125.         }  
  126.     }  
  127.   
  128. }  

 

  • 2
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值