如何更好地使用Java 8的Optional

Java 8中的Optional<T>

是一个可以包含或不可以包含非空值的容器对象,在 Stream API中很多地方也都使用到了Optional。

  java中非常讨厌的一点就是nullpoint,碰到空指针就会出错抛Exception,然后需要逐行检查是哪个对象为空,带来大量的不必要精力损耗,抛出NPE错误不是用户操作的错误,而是开发人员的错误,应该被避免,那么只能在每个方法中加入非空检查,阅读性和维护性都比较差。

  如下面这个代码的手工非空检查:

public void addAddressToCustomer(Customer customer, Address newAddress){

 if ( customer == null || newAddress == null)

 return;

 if ( customer.getAddresses() == null ){

   customer.setAddresses ( new ArrayList&lt;&gt;());

 }

 customer.addAddress(newAddress);

}

  另外还有一些开发人员喜欢通过非空检查来实现业务逻辑,空对象不应该用来决定系统的行为,它们是意外的Exceptional值,应当被看成是错误,而不是业务逻辑状态。

  当我们一个方法返回List集合时,应该总是返回一个空的List,而不是Null,这就允许调用者能够遍历它而不必检查Null,否则就抛出NPE。

  但是如果我们根据标识键ID查询数据库,没有查到,需要返回一个空对象怎么办?有人建议抛出Exception,其实这不符合函数方法一进一出的原则,变成一个函数方法有两个返回,一个是正常返回,一个出错Exception,函数式编程范式告诫我们不要轻易抛Exception。

  这时Java 8的Optional就发挥作用了,允许我们返回一个空的对象。

  Optional<T>有方法 isPresent() 和 get() 是用来检查其包含的对象是否为空或不是,然后返回它,如:

Optional<SomeType> someValue = someMethod();

if (someValue.isPresent()) { // check

someValue.get().someOtherMethod(); // retrieve and call

}

  但是这种用法并不能体现Java 8的全部好处,你可以将Optional看成是需要使用某个T值的方法之间某种中间人或者协调者Mediator,而不只是一个普通对象的包装器。

  如果你有一个值返回类型T,你有一个方法需要使用这个值,那么你可以让 Optional<T> 处于中间,确保它们之间交互进行,而不必要人工干预。

  这样,协调者Optional<T>能够照顾T的值提供给你的方法作为输入参数,在这种情况下,如果T是空,可以确保不会出错,这样在T值为空时也可以让一切都正常运作,你也可以让Optional<T>执行其他动作,如执行一段代码块等等,这样它就实际上是语言机制的很好的补充。

  下面这个案例涉及到Lambda表达式 方法引用,是将单词流中第一个以"L"开始单词取出,作为返回结果是一个Optional<String>。

使用ifPresent()

  这个案例的代码如下:

Stream<string> names = Stream.of("Lamurudu", "Okanbi", "Oduduwa");

Optional<string> longest = names

.filter(name -> name.startsWith("L"))

.findFirst();

longest.ifPresent(name -> {

String s = name.toUpperCase();

System.out.println("The longest name is "+ s);

});

  这里ifPresent() 是将一个Lambda表达式作为输入,T值如果不为空将传入这个lambda。那么这个lambda将不为空的单词转为大写输出显示。在前面names单词流寻找结果中,有可能找不到开始字母为L的单词,返回为空,也可能找到不为空,这两种情况都传入lambda中,无需我们打开盒子自己编写代码来判断,它自动帮助我们完成了,无需人工干预。

使用map()

  如果你想从Optional<T>中返回一个值怎么办?使用 map(),如下:

Stream<string> names = Stream.of("Lamurudu", "Okanbi", "Oduduwa");

Optional<string> longest = names

.filter(name -> name.startsWith("L"))

.findFirst();

Optional<string> lNameInCaps = longest.map(String::toUpperCase);

  使用Optional<T>的map方法能够返回另外一个Optional,如上面的 LnameInCaps,因为传入map()的参数值也许会导致一个空值。

使用orElse()

  如果在T可能空时你需要一个值的话,那么可以使用orElse(),它能在T值存在的情况下返回这个值,否则返回输入值。

Stream<String> names = Stream.of("Lamurudu", "Okanbi", "Oduduwa");

Optional<String> longest = names

.filter(name -> name.startsWith("Q"))

.findFirst();

String alternate = longest.orElse("Nimrod");

System.out.println(alternate); //prints out "Nimrod"

使用orElseGet()

  orElseGet() 方法类似于orElse(),但是不是直接返回输入参数,而是调用输入参数,返回调用的结果,这个输入参数通常是lambda:

Stream<String> names = Stream.of("Lamurudu", "Okanbi", "Oduduwa");

Optional<String> longest = names

.filter(name -> name.startsWith("Q"))

.findFirst();

String alternate = longest.orElseGet(() -> {

// perform some interesting code operation

// then return the alternate value.

return "Nimrod";

});

System.out.println(alternate);

使用 orElseThrow()

  orElseThrow()是在当遭遇Null时,决定抛出哪个Exception时使用:

Stream<String> names = Stream.of("Lamurudu", "Okanbi", "Oduduwa");

Optional<String> longest = names

.filter(name -> name.startsWith("Q"))

.findFirst();

longest.orElseThrow(NoSuchElementStartingWithQException::new);

总结,你能创建下面三种类型的Optional<T>:

Optional<SomeType> getSomeValue() {

// 返回一个空的Optional类型;

return Optional.empty();

}

Optional<SomeType> getSomeValue() {

SomeType value = ...;

// 使用这个方法,值不可以为空,否则抛exception

return Optional.of(value);

}

Optional<SomeType> getSomeValue() {

SomeType value = ...;

// 使用这个方法,值可以为空,如果为空返回Optional.empty

return Optional.ofNullable(value);

// usage

Optional<SomeType> someType = getSomeValue();

原文地址:https://www.cnblogs.com/zp-uestc/p/10304359.html

时间: 2024-11-05 17:18:54

如何更好地使用Java 8的Optional的相关文章

29个要点帮你更好的完成java代码优化

在Java程序中,性能问题的大部分原因并不在于Java语言,而是在于程序本身.养成好的代码编写习惯非常重要,比如正确地.巧妙地运用java.lang.String类和java.util.Vector类,它能够显著地提高程序的性能.下面我们就来具体地分析一下这方面的问题. 29个要点帮你更好的完成java代码优化 1. 尽量指定类的final修饰符 带有final修饰符的类是不可派生的. 在Java核心API中,有许多应用final的例子,例如java.lang.String.为String类指定

理解、学习与使用 Java 中的 Optional

从 Java 8 引入的一个很有趣的特性是 Optional  类.Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException) -- 每个 Java 程序员都非常了解的异常. 本质上,这是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象也可以为空. Optional 是 Java 实现函数式编程的强劲一步,并且帮助在范式中实现.但是 Optional 的意义显然不止于此. 我们从一个简单的用例开始.在 Java 8 之前,任何访问对

Java 8 (9) Optional取代null

NullPointerException,大家应该都见过.这是Tony Hoare在设计ALGOL W语言时提出的null引用的想法,他的设计初衷是想通过编译器的自动检测机制,确保所有使用引用的地方都是绝对安全的.很多年后,他对自己曾经做过的这个决定而后悔不已,把它称为"我价值百万的重大失误".它带来的后果就是---我们想判断一个对象中的某个字段进行检查,结果发现我们查看的不是一个对象,而是一个空指针,他会立即抛出NullPointerException异常. 看下面这个例子: pub

Tomcat上java.lang.IllegalStateException: Optional int parameter &#39;id&#39; is not present

今日, 本人在tomcat+spring mvc平台的服务器上遇到java.lang.IllegalStateException: Optional int parameter 'id' is not present异常, 很是怪异, mvc方法里面的id为int型, 明明是有值的, 为什么说没有? 改为Integer也不行, mvc方法直接无响应! 然后, 在本地模拟改用例, 发现可以正常执行, 而另一个同事说要把超长的图片参数放到Mvc方法的最后就可以正常访问! 怪异! 后来经过多次试验,

更好的理解java多线程

1.线程的创建 之前知道Java中一个多线程的创建方法是继承Thread类或者实现Runable接口,但是看不懂下面这种创建线程的方法 第一种 [java] view plain copy print? new Thread(new Runnable() { @Override public void run() { } } }).start();//这种方式中new Thread()是创建了一个线程,而new Runable()对象中是线程想要执行的代码,这样把想要执行的代码放到一个创建的对象

像Maven一样构建java项目的目录,更好的管理java工程的源码

都知道maven具有管理Java或者Javaweb的功能.我个人尤其看中的是其代码层次的分离.不同的代码在不同的文件夹下.这是在eclipse新建一个普通的工程无法实现的.而如果用maven实现有时候显得有点没有必要,特别是平时练习写代码的时候.能不能手动把普通的Java项目的目录结构修改为类似maven管理的项目的目录结构.这是当然可以的. Maven项目的目录结构: 从图中可以看出maven构建的Java web项目的目录很有层次感,src/main/java目录下存放的一般是项目的主要的代

如何更好的创建java对象(1)

上一篇我们意识到,在日常编码中,new方法常常被轻易的使用,但是某些场景下,对象实例不需要反复的创建,比如任务管理器.如果仍然使用new不断的创建对象,那必然浪费资源.由此我们来谈谈单例模式. 单例,即只存在单个实例.下面我们指的都是单应用下的单例. 想要实现单例,new不能对外界开放,所以构造方法需要设置为私有.同时为了外界访问,需要提供一个获取实例的方法.代码如下: public class Demo { private final Demo demo = new Demo(); priva

Java中利用Optional处理字符串转数字问题

最近在利用JavaFx开发时,由于没有只能输入数字的控件,每次都要对用户输入的string进行转换,但是Java中利用Double.parseDouble()方法转换时如果转化失败就会抛出异常,每次都try,catch很繁琐,而我在业余学习Swift时发现Swift的Optional和 as?的配合就可以极其优雅的解决这个问题,转换成功则获得该值,失败则为nil(Java里的null),而Java8也引入了Optional类,于是自己试着封装了一下,代码如下: public class Stri

java中的Optional类学习

Optional实际上是个容器,它是一个装一个对象的容器.这个对象可能是个空,可能是非空. Optional类可以使用来避免NullPointerException,避免频繁的判段对象为null的过程 1.创建Optional对象的方法: (1)Optional.of(xx); 只能装非空对象 (2)Optional.ofNullable(x); 装可以是null的对象 (3)Optional<T> empty() 直接返回一个空箱子对象 2.如何取出Optional容器中的对象 (1)get