Java8 Optional用法和最佳实践

根据Oracle文档,Optional是一个容器对象,能够包含也能够不包含非null值。Optional在Java 8中引入,目的是解决  NullPointerExceptions的问题。本质上,Optional是一个包装器类,其中包含对其余对象的引用。在这种状况下,对象只是指向内存位置的指针,而且也能够指向任何内容。从其它角度看,Optional提供一种类型级解决方案来表示可选值而不是空引用。java

Optional以前程序员

在Java 8以前,程序员将返回null而不是Optional。这种方法有一些缺点。一种是没有明确的方法来表示null多是一个特殊值。相比之下,在API中返回Optional是明确的声明,其中可能没有值。若是咱们要确保不会出现空指针异常,则须要对每一个引用进行显式的空检查,以下所示,咱们都赞成这是不少样板。数据库

// Life before Optional
    private void getIsoCode( User user){
        if (user != null) {
            Address address = user.getAddress();
            if (address != null) {
                Country country = address.getCountry();
                if (country != null) {
                    String isocode = country.getIsocode();
                    if (isocode != null) {
                        isocode = isocode.toUpperCase();
                    }
                }
            }
        }
    }

复制代码

为了简化此过程,让咱们看一下如何使用Optional类,从建立和验证明例到使用它提供的不一样方法并将其与返回相同类型的其余方法组合在一块儿,后者才是Optional的厉害之处。编程

Optional****的特性bash

Optional类提供了大约10种方法,咱们可使用它们来建立和使用Optional类,下面将介绍如何使用它们。编程语言

建立一个Optional函数

这是用于建立可选实例的三种建立方法。测试

1. static  [Optional] [empty]()ui

返回一个空的Optional实例。this

// Creating an empty optional
Optional<String> empty = Optional.empty();
复制代码

在返回一个空的{Optional}实例时,Optional的值不存在。不过,这样作可能颇有诱惑力,若是对象为空,请避免与Option.empty()返回的实例的{==}比较  。由于不能保证它是一个单例,反之,应该使用isPresent()。

2. static  [Optional] [of](T value)

返回特定的非空值Optional。

// Creating an optional using of

String name = "java";

Optional<String> opt = Optional.of(name);
复制代码

静态方法须要一个非null参数;不然,将引起空指针异常。所以,若是咱们不知道参数是否为null,那就是咱们使用  ofNullable的时候,下面将对此进行介绍。

3. static  [Optional] [of](T value)

返回描述指定值的Optional,若是非空,则返回空值。

// Possible null value

 Optional<String> optional = Optional.ofNullable(name());

  private  String  name(){

  String name = "Java";

  return (name.length() > 5) ? name : null;

 }
复制代码

若是咱们传入一个空引用,它不会抛出异常,而是返回一个空的Optional对象:

因此这就是动态或手动建立Optional的三种方法。下一组方法用于检查值的存在。

1. 布尔值**[isPresent]****()**

若是存在值,则返回true;反之,返回false。若是所包含的对象不为null,则返回true,反之返回false。一般在对对象执行任何其余操做以前,先在Optional上调用此方法。 ··· //ispresent

Optional optional1 = Optional.of("javaone");

if (optional1.isPresent()){

//Do something, normally a get

} ··· 2. 布尔值[isEmpty()]

若是存在值,则返回false;不然,返回ture。这与isPresent 相反,  而且仅在Java 11及更高版本中可用。

//isempty

Optional<String> optional1 = Optional.of("javaone");

if (optional1.isEmpty()){

  //Do something

}
复制代码

3. void [ifPresent]([Consumer]<? super [T]> consumer)

若是存在值,则使用该值调用指定的使用者;不然,什么都不作。

若是您不熟悉Java 8,那么您可能会想知道:什么是消费者?简单来讲,消费者是一种接受参数且不返回任何内容的方法。当使用  ifPresent时,这个方法就是一石二鸟。咱们能够执行值存在性检查并使用一种方法执行预期的操做,以下所示。

//ifpresent

Optional<String> optional1 = Optional.of("javaone");

optional1.ifPresent(s -> System.out.println(s.length()));
复制代码

可选类提供了另外一组用于获取可选值的方法。

1. T[get]()

若是此Optional中存在值,则返回该值,不然抛出  NoSuchElementException。在这以后,咱们想要的是存储在Optional中的值,咱们能够经过get()来获取它。可是,当该值为null时,此方法将引起异常。这就须要  orElse() 方法来紧急救援。

//get
Optional<String> optional1 = Optional.of("javaone");
if (optional1.isPresent()){ 
  String value = optional1.get();
}
复制代码

2. [][orElse][T]其余)

返回值(若是存在);反之,返回其余。

该  orElse() 方法用于检索包装在Optional实例内的值。它采用一个充当默认值的参数。该  orElse() 方法返回包装的值(若是存在)及其参数,反之:

//orElse
        String nullName = null;
        String name = Optional.ofNullable(nullName).orElse("default_name");

复制代码

若是这还不够,那么Optional类将继续提供另外一种获取值的方法,即便该方法的null称为 orElseGet()。

3. [T][orElseGet]([Supplier]<? extends [T]> other)

返回值(若是存在);不然,调用other并返回该调用的结果。

该orElseGet() 方法相似于 orElse()。可是,若是没有Optional值,则不采用返回值,而是采用供应商功能接口,该接口将被调用并返回调用的值:

//orElseGet
        String name = Optional.ofNullable(nullName).orElseGet(() -> "john");

复制代码

那么,orElse() 和orElseGet()之间有什么区别。

乍一看,这两种方法彷佛具备相同的效果。可是,事实并不是如此。让咱们建立一些示例,以突出二者之间的类似性和行为差别。

首先,让咱们看看它们在对象为空时的行为:

String text = null;
String defaultText = Optional.ofNullable(text).orElseGet(this::getDefaultValue);
defaultText = Optional.ofNullable(text).orElse(getDefaultValue());
public String getDefaultValue() {
    System.out.println("Getting Default Value");
    return "Default Value";
}

复制代码

在上面的示例中,咱们在Optional对象中包装了一个空文本,而后尝试使用两种方法中的每一种来获取包装后的值。反作用以下:

Getting default value...
Getting default value...
复制代码

在每种状况下都会调用默认方法。碰巧的是,当不存在包装的值时,二者  orElse() 和的  orElseGet() 工做方式彻底相同。

如今,让咱们运行另外一个该值存在测试,理想状况下,甚至不该建立默认值:

在这个简单的示例中,建立默认对象不会花费不少成本,由于JVM知道如何处理此类对象。可是,当诸如此类的方法  default 必须进行Web服务调用或者查询数据库时,则成本变得很是明显。

使用Optional最佳实践

就像编程语言的任何其余功能同样,它能够正确使用或被滥用。为了了解使用Optional类的最佳方法,须要了解如下内容:

**1.**它解决的问题

Optional的方法是尝试经过增长构建更具表现力的API的可能性来减小Java系统中空指针异常的状况,这些API解释了有时缺乏返回值的可能性。

若是从一开始就存在Optional,那么大多数库和应用程序可能会更好地处理缺乏的返回值,从而减小了空指针异常的数量以及整体上的错误总数。

**2.**它不解决的问题

Optional并不意味着是一种避免全部类型的空指针的机制。例如,它仍然必须测试方法和构造函数的强制输入参数。

像使用null时同样,Optional不能帮助传达缺失值的含义。以相似的方式,null可能意味着不少不一样的东西(找不到值等),所以缺乏Optional值也能够。

该方法的调用方仍然须要检查该方法的JavaDoc以理解缺省选项的含义,以便正确地处理它。

一样,以一种相似的方式,能够将检查的异常捕获在一个空块中,没有什么阻止调用方进行调用  get() 并继续进行。

**3.**什么时候使用

Optional的预期用途主要是做为返回类型。获取此类型的实例后,能够提取该值(若是存在)或提供其余行为(若是不存在)。

Optional类的一个很是有用的用例是将其与流或返回Optional值以构建流畅的API的其余方法结合。请参见下面的代码段

User user = users.stream().findFirst().orElse(new User("default", "1234"));
复制代码

**4.**何时不使用

a)不要将其用做类中的字段,由于它不可序列化

若是确实须要序列化包含Optional值的对象,则Jackson库提供了将Optionals视为普通对象的支持。这意味着Jackson将空对象视为空,将具备值的对象视为包含该值的字段。能够在jackson-modules-java8项目中找到此功能。

b)不要将其用做构造函数和方法的参数,由于这会致使没必要要的复杂代码。

User user = new User("john@gmail.com", "1234", Optional.empty());
复制代码

本人创业团队产品MadPecker,主要作BUG管理、测试管理、应用分发 网址:[www.madpecker.com],有须要的朋友欢迎试用、体验! 本文为MadPecker团队技术人员译制,转载请标明出处

相关文章
相关标签/搜索