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;
}
}

这篇写的很好,另外参考Java8实战

http://blog.csdn.net/sun_promise/article/details/51362838

Java8实战的一个例子

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 异常,我们经常会写出这样的代码:

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

使用Optional的代码写法:

  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:

  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:

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

3) isPresent()

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

eg:

  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:

  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:

  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:

  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:

  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:

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

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

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

eg:

  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重写的示例

  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:

  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. //另一个例子是Optional值不满足filter指定的条件。
  6. Optional<String> anotherName = Optional.of("Test");
  7. Optional<String> shortName = anotherName.filter((value) -> value.length() > 6);
  8. //输出:name长度不足6字符
  9. System.out.println(shortName.orElse("The name is less than 6 characters"));

12) empty()

返回一个空Optional实例。

eg:

  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:

  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的新特性,需要配置很多东西,也一样容易出现各种问题。

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

optional的更多相关文章

  1. [翻译]理解Swift中的Optional

    原文出处:Understanding Optionals in Swift 苹果新的Swift编程语言带来了一些新的技巧,能使软件开发比以往更方便.更安全.然而,一个很有力的特性Optional,在你 ...

  2. Atitit. null错误的设计 使用Optional来处理null

    Atitit. null错误的设计 使用Optional来处理null 然后,我们再看看null还会引入什么问题. 看看下面这个代码: String address = person.getCount ...

  3. Guava学习笔记(1):Optional优雅的使用null

    转自:http://www.cnblogs.com/peida/archive/2013/06/14/Guava_Optional.html 参考:[Google Guava] 1.1-使用和避免nu ...

  4. guava – Optional

    过多的使用null可能会导致大量的bugs,Google code 底层代码中,95%的集合类默认不接受null值.对null值,使用快速失败拒绝null比默认接受更好. 另外,null本身的含义很模 ...

  5. JAVA 8 Optional类介绍及其源码

    什么是Optional对象 Java 8中所谓的Optional对象,即一个容器对象,该对象可以包含一个null或非null值.如果该值不为null,则调用isPresent()方法将返回true,且 ...

  6. maven可选依赖(Optional Dependencies)和依赖排除(Dependency Exclusions)

    我们知道,maven的依赖关系是有传递性的.如:A-->B,B-->C.但有时候,项目A可能不是必需依赖C,因此需要在项目A中排除对A的依赖.在maven的依赖管理中,有两种方式可以对依赖 ...

  7. Java 8 Optional类深度解析

    身为一名Java程序员,大家可能都有这样的经历:调用一个方法得到了返回值却不能直接将返回值作为参数去调用别的方法.我们首先要判断这个返回值是否为null,只有在非空的前提下才能将其作为其他方法的参数. ...

  8. Swift中的Optional类型 (可选类型)与强制解包 ? !

    我们在swift的开发中会经常遇见?和! ,理解这两个符号深层次的内容对我们的开发是相当有利的: 目前网上对swift3.0的教程还相当的少,如果去搜索会发现早期的说法,在定义变量的时候,swift是 ...

  9. Swift开发第五篇——四个知识点(Struct Mutable方法&Tuple&autoclosure&Optional Chain)

    本篇分三部分: 一.Struct Mutable方法 二.多元组(Tuple) 的使用 三.autoclosure 的使用 四.Optional Chain 的使用 一.Struct Mutable方 ...

  10. initializer for conditional binding must have optional type not AVAudioPlayer

    if let buttonBeep = self.setupAudioPlayerWithFile("ButtonTap", type: "wav") {    ...

随机推荐

  1. 【输入法】Rime-中州韵 基本设置 附:官方定制指南

    前言 不知不觉就到了年终了,距离上次更新博客已经有一个半月,这段时间天天在加班,也没作一下新的学习计划,趁着元旦放假,写一点好玩的东西,这次要记录的是一点关于Rime相关的东西,文章本身不会长,只是说 ...

  2. MyBatis向数据库中批量插入数据

    Foreach标签 foreach: collection:指定要遍历的集合; 表示传入过来的参数的数据类型.该参数为必选.要做 foreach 的对象,作为入参时,List 对象默认用 list 代 ...

  3. log4j2 的使用

    log4j2 是 log4j 的升级,更为方便,更为强大. log4j2.xml 的配置以及 log4j2的依赖包使用log4j2 并没有其他的依赖包,只是在使用log4j的情况下,需要别的进行桥接 ...

  4. CF912E Prime Gift

    传送门 看到\(n\)只有16,可以把这些质数分成两半,然后预处理出这些数相乘得出的小于\(10^{18}\)的所有数,排个序,然后二分最终答案,再用两个指针从前往后和从后往前扫,进行\(two-po ...

  5. 修改weblogic的端口

    两种方法可以修改,第一种方法是后台管理界面修改,第二种是配置文件修改,下面分别介绍: 1.后台修改 (1)进入weblogic登陆界面:(默认端口是7001) (2)登陆之后点击服务器----然后管理 ...

  6. chattr的使用

    让某个文件只能往里面追加内容,不能删除,一些日志文件适用于这种操作: chattr +a /home/caolei/.bash_history 查看lsattr /home/caolei/.bash_ ...

  7. 常用css样式(布局)

    兼容css3新属性 在css3中,我们可以使用prefixfree.min.js这个插件来自动为css3的相关属性加上兼容浏览器属性,使我们不用为每个css3新属性再加上属性(需要用到大量css3的项 ...

  8. ES系列九、ES优化聚合查询之深度优先和广度优先

    1.优化聚合查询示例 假设我们现在有一些关于电影的数据集,每条数据里面会有一个数组类型的字段存储表演该电影的所有演员的名字. { "actors" : [ "Fred J ...

  9. 026_关于shell中的特殊变量$0 $n $* $@ $! $?

    一. $n:获取当前执行的shell脚本的第N个参数,n=1..9,当n为0时表示脚本的文件名,如果n大于9,用大括号括起来like${10}. $*:获取当前shell的所有参数,将所有的命令行参数 ...

  10. jQuery版本的jsonp

    1.一个众所周知的问题,Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面.动态网页.web服务.WCF,只要是跨域请求,一律不准: 2.不过我们又发现,Web页面上调用js文件时则不 ...