如何很“礼貌”的避免抛出空指针异常

如 何 很 “ 礼 貌 ” 的 避 免 抛 出 空 指 针 异 常 ​ \color{#FF0000}{如何很“礼貌”的避免抛出空指针异常} ​

摘要

说到空指针,是猿宝宝们最头疼的问题(赞同的评论区 “ + 1 ” \color{#FF0000}{“+1”} +1哦),这篇文章教大家如何很“礼貌”的避免抛出空指针异常,大家此时此刻有个疑问,怎么个礼貌发,那么大招来了,大家装备都升级了吧,以免我放大招伤到猿宝宝,哈哈哈,那就是 J D K 1.8 自 动 新 特 性 O p t i o n a l \color{#FF0000}{JDK1.8自动新特性Optional} JDK1.8Optional,到这里不得不说 J D K 爸 爸 牛 扒 \color{#FF00EE}{JDK爸爸牛扒} JDK… …

1.概述

概述不多说了,主要是jdk中的这个类

import java.util.Optional;

2.如何创建Optional

有几种创建可选对象的方法。要创建一个空的Optional对象,我们只需要使用其空的static方法

package xyz.mrzhangxd.optionaltest;
​
@Test
public void whenCreatesEmptyOptional_thenCorrect() {
    Optional<String> empty = Optional.empty();
    assertFalse(empty.isPresent());
}

猿宝宝们注意了,我们使用了isPresent()方法来检查Optional对象中是否有一个值。仅当我们使用非空值创建Optional时,该值才存在。我们将在下一节中讨论isPresent方法。

我们还可以使用以下静态方法创建Optional对象:

package xyz.mrzhangxd.optionaltest;
​
@Test
public void givenNonNull_whenCreatesNonNullable_thenCorrect() {
    String userName = "MrZhangxd";
    Optional<String> opt = Optional.of(userName);
    assertTrue(opt.isPresent());
}

在这里,我得插一嘴了,传递给of()方法的参数不能为null。否则,我们将获得NullPointerException:

package xyz.mrzhangxd.optionaltest;
​
@Test(expected = NullPointerException.class)
public void givenNull_whenThrowsErrorOnCreate_thenCorrect() {
    String userName = null;
    Optional.of(userName);
}

但是,如果我们期望某些空值,则可以使用ofNullable()方法:

package xyz.mrzhangxd.optionaltest;
​
@Test
public void givenNonNull_whenCreatesNullable_thenCorrect() {
    String userName = "MrZhangxd";
    Optional<String> opt = Optional.ofNullable(userName);
    assertTrue(opt.isPresent());
}

通过ofNullable()方法这样做,如果我们在一个空引用传递,它不抛出一个异常,而是返回一个空的可选对象

package xyz.mrzhangxd.optionaltest;
​
@Test
public void givenNull_whenCreatesNullable_thenCorrect() {
    String userName = null;
    Optional<String> opt = Optional.ofNullable(userName);
    assertFalse(opt.isPresent());
}

3.检查值是否存在:isPresent()和isEmpty()

当我们有一个从方法返回或由我们创建的Optional对象时,我们可以使用isPresent()方法检查其中是否有值

package xyz.mrzhangxd.optionaltest;
​
@Test
public void givenOptional_whenIsPresentWorks_thenCorrect() {
    Optional<String> opt = Optional.of("MrZhangxd");
    assertTrue(opt.isPresent());
 
    opt = Optional.ofNullable(null);
    assertFalse(opt.isPresent());
}

如果包装的值不为null,则此方法返回true。

另外,从Java 11开始,我们可以使用isEmpty方法执行相反的操作

package xyz.mrzhangxd.optionaltest;
​
@Test
public void givenAnEmptyOptional_thenIsEmptyBehavesAsExpected() {
    Optional<String> opt = Optional.of("My name is MrZhangxd");
    assertFalse(opt.isEmpty());
 
    opt = Optional.ofNullable(null);
    assertTrue(opt.isEmpty());
}

4.使用ifPresent()的条件操作

如果发现包装值非空,则ifPresent()方法使我们能够对包装值运行一些代码。。

if(userName != null) {
    System.out.println(userName.length());
}

此代码在继续执行一些代码之前检查userName变量是否为null。这种方法很冗长,这不是唯一的问题,也容易出错。

确实,可以保证的是,在打印完该变量后,我们将不再使用它,然后忘记执行空检查。

如果在该代码中找到空值,则可能在运行时导致NullPointerException。当程序由于输入问题而失败时,通常是由于不良的编程习惯造成的。

可选使我们可以显式处理可空值,作为执行良好编程习惯的一种方式。现在让我们看一下如何在Java 8中重构以上代码。

在典型的函数式编程风格中,我们可以对实际存在的对象执行操作。

package xyz.mrzhangxd.optionaltest;
​
@Test
public void givenOptional_whenIfPresentWorks_thenCorrect() {
    Optional<String> opt = Optional.of("MrZhangxd");
    opt.ifPresent(userName -> System.out.println(userName.length()));
}

在上面的示例中,我们仅使用两行代码来替换第一个示例中的七行代码。一行将对象包装到Optional对象中,另一行执行隐式验证以及执行代码。

5.使用orElse()的默认值

orElse()方法用于检索包装在Optional实例内的值。它采用一个参数作为默认值。 orElse()方法返回包装的值(如果存在),否则返回其参数。

package xyz.mrzhangxd.optionaltest;
​
@Test
public void whenOrElseWorks_thenCorrect() {
    String nullName = null;
    String userName = Optional.ofNullable(nullName).orElse("MrZhangxd");
    assertEquals("MrZhangxd", userName);
}

6.使用orElseGet()的默认值

orElseGet()方法类似于orElse()。但是,如果没有提供Optional值,则不采用返回值,而是采用供应商功能接口,该接口将被调用并返回调用的值.

package xyz.mrzhangxd.optionaltest;
​
@Test
public void whenOrElseGetWorks_thenCorrect() {
    String nullName = null;
    String userName = Optional.ofNullable(nullName).orElseGet(() -> "MrZhangxd");
    assertEquals("MrZhangxd", userName);
}

7. orElse和orElseGet()之间的区别

对于Optional或Java 8的新手来说,orElse()和orElseGet()之间的区别尚不清楚。实际上,这两种方法给人的印象是它们在功能上相互重叠。

但是,如果不了解的话,两者之间会有细微但非常重要的区别,这可能会严重影响我们的代码性能。

让我们在测试类中创建一个名为getMyDefault()的方法,该方法不带任何参数并返回默认值.

package xyz.mrzhangxd.optionalproject;
​
public String getMyDefault() {
    System.out.println("Getting Default Value");
    return "Default Value";
}

让我们看两个测试并观察它们的作用,以确定orElse()和orElseGet()重叠的地方以及它们的不同之处.

package xyz.mrzhangxd.optionaltest;
​
import xyz.mrzhangxd.optionalproject;
​
@Test
public void whenOrElseGetAndOrElseOverlap_thenCorrect() {
    String text = null;
 
    String defaultText = Optional.ofNullable(text).orElseGet(this::getMyDefault);
    assertEquals("Default Value", defaultText);
 
    defaultText = Optional.ofNullable(text).orElse(getMyDefault());
    assertEquals("Default Value", defaultText);
}

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

Getting default value...
Getting default value...

在每种情况下都会调用getMyDefault()方法。碰巧的是,当不存在包装的值时,orElse()和orElseGet()都以完全相同的方式工作。

现在让我们运行另一个测试,其中存在该值,理想情况下,甚至不应创建默认值.

package xyz.mrzhangxd.optionaltest;
​
import xyz.mrzhangxd.optionalproject;
​
@Test
public void whenOrElseGetAndOrElseDiffer_thenCorrect() {
    String text = "Text present";
 
    System.out.println("Using orElseGet:");
    String defaultText 
      = Optional.ofNullable(text).orElseGet(this::getMyDefault);
    assertEquals("Text present", defaultText);
 
    System.out.println("Using orElse:");
    defaultText = Optional.ofNullable(text).orElse(getMyDefault());
    assertEquals("Text present", defaultText);
}

在上面的示例中,我们不再包装空值,其余代码保持不变。现在,让我们看一下运行此代码的作用:

Using orElseGet:
Using orElse:
Getting default value...

猿宝宝们注意啦,使用orElseGet()检索包装的值时,由于存在包含的值,因此甚至不会调用getMyDefault()方法。

但是,使用orElse()时,无论是否存在包装的值,都会创建默认对象。因此,在这种情况下,我们仅创建了一个从未使用过的冗余对象。

在这个简单的示例中,创建默认对象不会花费很多成本,因为JVM知道如何处理此类对象。但是,当诸如getMyDefault()之类的方法必须进行Web服务调用或什至查询数据库时,则成本变得非常明显。

8. orElseThrow()的异常

orElseThrow()方法紧随orElse()和orElseGet()之后,并添加了一种新方法来处理缺少的值。当包装值不存在时,它不会返回默认值,而是会引发异常。

package xyz.mrzhangxd.optionaltest;
​
@Test(expected = IllegalArgumentException.class)
public void whenOrElseThrowWorks_thenCorrect() {
    String nullName = null;
    String userName = Optional.ofNullable(nullName).orElseThrow(
      IllegalArgumentException::new);
}

Java 8中的方法引用在这里很方便,可以传入异常构造函数。

9.使用get()返回值

检索包装值的最终方法是get()方法.

package xyz.mrzhangxd.optionaltest;
​
@Test
public void givenOptional_whenGetsValue_thenCorrect() {
    Optional<String> opt = Optional.of("baeldung");
    String name = opt.get();
    assertEquals("baeldung", name);
}

但是,与上述三种方法不同,get()仅在包装的对象不为null时才能返回值,否则,将引发no这样的元素异常。

package xyz.mrzhangxd.optionaltest;
​
@Test(expected = NoSuchElementException.class)
public void givenOptionalWithNull_whenGetThrowsException_thenCorrect() {
    Optional<String> opt = Optional.ofNullable(null);
    String userName = opt.get();
}

这是get()方法的主要缺陷。理想情况下,Optional应该可以帮助我们避免此类不可预见的异常。因此,此方法违背Optional的目标,并且可能在以后的版本中弃用。

因此,建议使用其他变量,这些变量使我们能够准备并显式处理null情况。这是get()方法的主要缺陷。理想情况下,Optional应该可以帮助我们避免此类不可预见的异常。因此,此方法违背Optional的目标,并且可能在以后的版本中弃用。

因此,建议使用其他变体,这些变体使我们能够准备并显式处理空情况。

10.带filter()的条件返回

我们可以使用filter方法对包装的值进行内联测试。它以谓词作为参数,并返回Optional对象。如果包装的值通过谓词的测试,则按原样返回Optional。

但是,如果谓词返回false,则它将返回空的Optional.

package xyz.mrzhangxd.optionaltest;
​
@Test
public void whenOptionalFilterWorks_thenCorrect() {
    Integer year = 2019;
    Optional<Integer> yearOptional = Optional.of(year);
    boolean is2019 = yearOptional.filter(y -> y == 2019).isPresent();
    assertTrue(is2019);
    boolean is2020 = yearOptional.filter(y -> y == 2020).isPresent();
    assertFalse(is2020);
}

通常以这种方式使用filter方法来基于预定义规则拒绝包装的值。我们可以使用它来拒绝错误的电子邮件格式或强度不够的密码。

让我们看另一个有意义的例子。假设我们要购买调制解调器,而我们只关心它的价格。我们从某个站点接收有关调制解调器价格的推送通知,并将其存储在对象中.

package xyz.mrzhangxd.optionalproject;
​
public class Modem {
    private Double price;
 
    public Modem(Double price) {
        this.price = price;
    }
    // standard getters and setters
}

然后,我们将这些对象提供给某些代码,其唯一目的是检查调制解调器的价格是否在我们预算的范围内。

现在让我们看一下没有Optional的代码.

package xyz.mrzhangxd.optionalproject;
​
public boolean priceIsInRange1(Modem modem) {
    boolean isInRange = false;
 
    if (modem != null && modem.getPrice() != null
      && (modem.getPrice() >= 10
        && modem.getPrice() <= 15)) {
 
        isInRange = true;
    }
    return isInRange;
}

猿宝宝们注意要实现此目的必须编写多少代码,尤其是在if条件下。如果条件对应用程序至关重要,则唯一的部分是最后的价格范围检查;其余的检查是防御性的。

package xyz.mrzhangxd.optionaltest;
​
import xyz.mrzhangxd.optionalproject.priceIsInRange1;
import xyz.mrzhangxd.optionalproject.Modem;
​
@Test
public void whenFiltersWithoutOptional_thenCorrect() {
    assertTrue(priceIsInRange1(new Modem(10.0)));
    assertFalse(priceIsInRange1(new Modem(9.9)));
    assertFalse(priceIsInRange1(new Modem(null)));
    assertFalse(priceIsInRange1(new Modem(15.5)));
    assertFalse(priceIsInRange1(null));
}
除此之外,很可能会忘记一整天的空检查而不会出现任何编译时错误。

现在让我们看一下带有Optional#filter的变体.

 

package xyz.mrzhangxd.optionalproject;
​
public boolean priceIsInRange2(Modem modem2) {
     return Optional.ofNullable(modem2)
       .map(Modem::getPrice)
       .filter(p -> p >= 10)
       .filter(p -> p <= 15)
       .isPresent();
 }

映射调用仅用于将一个值转换为其他值。请记住,此操作不会修改原始值。

在我们的例子中,我们从Model类中获取一个价格对象。在下一节中,我们将详细介绍map()方法。

首先,如果将null对象传递给此方法,则不会有任何问题。

其次,我们在其主体内编写的唯一逻辑就是方法名称所描述的,即价格范围检查。可选的照顾其余的.

package xyz.mrzhangxd.optionaltest;
​
import xyz.mrzhangxd.optionalproject.priceIsInRange2;
import xyz.mrzhangxd.optionalproject.Modem;
​
@Test
public void whenFiltersWithOptional_thenCorrect() {
    assertTrue(priceIsInRange2(new Modem(10.0)));
    assertFalse(priceIsInRange2(new Modem(9.9)));
    assertFalse(priceIsInRange2(new Modem(null)));
    assertFalse(priceIsInRange2(new Modem(15.5)));
    assertFalse(priceIsInRange2(null));
}

先前的方法有望检查价格范围,但除了防御其固有的脆弱性外,还必须做更多的事情。因此,我们可以使用filter方法替换不必要的if语句并拒绝不需要的值。

11.使用map()转换价值

在上面,我们研究了如何基于过滤器拒绝或接受值。我们可以使用类似的语法通过map()方法转换Optional值。

package xyz.mrzhangxd.optionaltest;
​
​
@Test
public void givenOptional_whenMapWorks_thenCorrect() {
    List<String> companyNames = Arrays.asList(
      "京东", "阿里巴巴", "", "华为", "", "苹果");
    Optional<List<String>> listOptional = Optional.of(companyNames);
 
    int size = listOptional
      .map(List::size)
      .orElse(0);
    assertEquals(6, size);
}

在此示例中,我们将字符串列表包装在Optional对象中,并使用其map方法对包含的列表执行操作。我们执行的操作是检索列表的大小。

map方法返回包装在Optional中的计算结果。然后,我们必须在返回的Optional上调用适当的方法以获取其值。

请注意,filter方法仅对值进行检查并返回布尔值。另一方面,map方法采用现有值,使用该值执行计算,然后返回包装在Optional对象中的计算结果。

package xyz.mrzhangxd.optionaltest;
​
@Test
public void givenOptional_whenMapWorks_thenCorrect2() {
    String userName = "MrZhangxd";
    Optional<String> nameOptional = Optional.of(userName);
 
    int len = nameOptional
     .map(String::length)
     .orElse(0);
    assertEquals(8, len);
}

我们可以将地图和过滤器链接在一起,以执行更强大的操作。

假设我们要检查用户输入的密码是否正确;我们可以使用地图转换清除密码,并使用过滤器检查密码的正确性.

package xyz.mrzhangxd.optionaltest;
​
@Test
public void givenOptional_whenMapWorksWithFilter_thenCorrect() {
    String password = " password ";
    Optional<String> passOpt = Optional.of(password);
    boolean correctPassword = passOpt.filter(
      pass -> pass.equals("password")).isPresent();
    assertFalse(correctPassword);
 
    correctPassword = passOpt
      .map(String::trim)
      .filter(pass -> pass.equals("password"))
      .isPresent();
    assertTrue(correctPassword);
}

如果不先清除输入内容,就会将其过滤掉-但是用户可能会认为前导空格和尾随空格都构成了输入。因此,在过滤掉不正确的密码之前,我们先将带有映射的脏密码转换为干净的密码。

12.使用flatMap()转换价值

就像map()方法一样,我们也有flatMap()方法作为转换值的替代方法。区别在于,地图仅在展开值时才转换值,而flatMap会在转换值之前采用已包装的值并对其进行解包。

以前,我们创建了简单的String和Integer对象,用于包装在Optional实例中。但是,通常,我们将从复杂对象的访问者那里接收这些对象。

为了更清楚地了解两者之间的区别,让我们看一下一个Person对象,该对象带有一个人的详细信息,例如姓名,年龄和密码等。

package xyz.mrzhangxd.optionalproject;
​
public class Person {
    private String name;
    private int age;
    private String password;
 
    public Optional<String> getName() {
        return Optional.ofNullable(name);
    }
 
    public Optional<Integer> getAge() {
        return Optional.ofNullable(age);
    }
 
    public Optional<String> getPassword() {
        return Optional.ofNullable(password);
    }
 
    // normal constructors and setters
}

我们通常会创建一个这样的对象并将其包装在Optional对象中,就像处理String一样。或者,可以通过另一个方法调用将其返回给我们.

Person person = new Person("MrZhangxd", 18);
Optional<Person> personOptional = Optional.of(person);

当包装一个Person对象时,它将包含嵌套的Optional实例.

package xyz.mrzhangxd.optionaltest;
​
import xyz.mrzhangxd.optionalproject.Person;
​
@Test
public void givenOptional_whenFlatMapWorks_thenCorrect2() {
    Person person = new Person("MrZhangxd", 18);
    Optional<Person> personOptional = Optional.of(person);
 
    Optional<Optional<String>> nameOptionalWrapper  
      = personOptional.map(Person::getName);
    Optional<String> nameOptional  
      = nameOptionalWrapper.orElseThrow(IllegalArgumentException::new);
    String name1 = nameOptional.orElse("");
    assertEquals("MrZhangxd", name1);
 
    String name = personOptional
      .flatMap(Person::getName)
      .orElse("");
    assertEquals("MrZhangxd", name);
}

接下来,我们试图检索Person对象的name属性以执行断言。

注意在第三条语句中如何使用map()方法实现此目的,然后注意之后如何使用flatMap()方法来实现此目的。

Person :: getName方法的引用类似于上一节中用于清理密码的String :: trim调用。

唯一的区别是getName()返回的是Optional而不是String,与trim()操作一样。这加上映射转换将结果包装在Optional对象中的事实导致嵌套的Optional。

因此,在使用map()方法时,我们需要在使用转换后的值之前添加一个额外的调用来检索值。这样,可选包装将被删除。使用flatMap时,将隐式执行此操作。

13. Java 8中的可选链接

有时,我们可能需要从多个Optional中获取第一个非空的Optional对象。在这种情况下,使用类似orElseOptional()的方法将非常方便。不幸的是,Java 8不直接支持这种操作。

让我们首先介绍在本节中将要使用的一些方法.

private Optional<String> getEmpty() {
    return Optional.empty();
}
 
private Optional<String> getHello() {
    return Optional.of("hello");
}
 
private Optional<String> getBye() {
    return Optional.of("bye");
}
 
private Optional<String> createOptional(String input) {
    if (input == null || "".equals(input) || "empty".equals(input)) {
        return Optional.empty();
    }
    return Optional.of(input);
}

为了链接多个Optional对象并获得Java 8中的第一个非空对象,我们可以使用Stream API

package xyz.mrzhangxd.optionaltest;
​
@Test
public void givenThreeOptionals_whenChaining_thenFirstNonEmptyIsReturned() {
    Optional<String> found = Stream.of(getEmpty(), getHello(), getBye())
      .filter(Optional::isPresent)
      .map(Optional::get)
      .findFirst();
     
    assertEquals(getHello(), found);
}

这种方法的缺点是,无论Stream中非空Optional出现在何处,我们所有的get方法都始终执行。

如果我们想懒惰地评估传递给Stream.of()的方法,则需要使用方法参考和Supplier接口.

package xyz.mrzhangxd.optionaltest;
​
@Test
public void givenThreeOptionals_whenChaining_thenFirstNonEmptyIsReturnedAndRestNotEvaluated() {
    Optional<String> found =
      Stream.<Supplier<Optional<String>>>of(this::getEmpty, this::getHello, this::getBye)
        .map(Supplier::get)
        .filter(Optional::isPresent)
        .map(Optional::get)
        .findFirst();
 
    assertEquals(getHello(), found);
}

如果需要使用带有参数的方法,则必须求助于lambda表达式.

package xyz.mrzhangxd.optionaltest;
​
@Test
public void givenTwoOptionalsReturnedByOneArgMethod_whenChaining_thenFirstNonEmptyIsReturned() {
    Optional<String> found = Stream.<Supplier<Optional<String>>>of(
      () -> createOptional("empty"),
      () -> createOptional("hello")
    )
      .map(Supplier::get)
      .filter(Optional::isPresent)
      .map(Optional::get)
      .findFirst();
 
    assertEquals(createOptional("hello"), found);
}

通常,在所有链接的Optionals为空的情况下,我们通常希望返回一个默认值。我们可以通过添加对orElse()或orElseGet()的调用来做到这一点,如以下示例所示.

package xyz.mrzhangxd.optionaltest;
​
@Test
public void givenTwoEmptyOptionals_whenChaining_thenDefaultIsReturned() {
    String found = Stream.<Supplier<Optional<String>>>of(
      () -> createOptional("empty"),
      () -> createOptional("empty")
    )
      .map(Supplier::get)
      .filter(Optional::isPresent)
      .map(Optional::get)
      .findFirst()
      .orElseGet(() -> "default");
 
    assertEquals("default", found);
}

14. JDK 9可选API

Java 9的发行版为Optional API添加了更多新方法

or()方法,用于提供创建替代项的供应商;
ifPresentOrElse()方法,如果存在Optional,则允许执行一个动作;否则,则允许另一个动作;
stream()方法,用于将Optional转换为Stream.

15.滥用Optional

最后,让我们看看使用Optionals的一种诱人但危险的方法:将Optional参数传递给方法。

想象一下,我们有一个“人”列表,并且我们希望有一种方法可以在该列表中搜索具有给定名称的人。另外,如果指定了年龄,我们希望该方法匹配至少具有一定年龄的条目。由于此参数是可选的,因此我们提供了以下方法。

public List<Person> search(List<Person> people, String name, Optional<Integer> age) {
    // Null checks for people and name
    people.stream()
      .filter(p -> p.getName().equals(name))
      .filter(p -> p.getAge() >= age.orElse(0))
      .collect(Collectors.toList());
}

然后,我们释放我们的方法,让另一个开发人员尝试使用它.

someObject.search(people, “MrZhangxd”, null);
现在,开发人员执行其代码并获取NullPointerException。在这里,我们必须对我们的可选参数进行空检查,这在想要避免这种情况时违背了我们的初衷。

我们可能会做一些更好的处理方法。

public List<Person> search(List<Person> people, String name, Integer age) {
    // Null checks for people and name
 
    age = age != null ? age : 0;
    people.stream()
      .filter(p -> p.getName().equals(name))
      .filter(p -> p.getAge() >= age)      
      .collect(Collectors.toList());
}

该参数仍然是可选的,但是我们仅需检查一下即可处理它。另一种可能性是创建两个重载方法.

public List<Person> search(List<Person> people, String name) {
    return doSearch(people, name, 0);
}
 
public List<Person> search(List<Person> people, String name, int age) {
    return doSearch(people, name, age);
}
 
private List<Person> doSearch(List<Person> people, String name, int age) {
    // Null checks for people and name
    return people.stream()
      .filter(p -> p.getName().equals(name))
      .filter(p -> p.getAge() >= age)
      .collect(Collectors.toList());
}

这样,我们提供了一个清晰的API,其中包含两种可以完成不同任务的方法(尽管它们共享实现)。

因此,有一些解决方案可以避免使用Optionals作为方法参数。发行Optional时,Java的意图是将其用作返回类型,从而表明一种方法可以返回空值。实际上,某些代码检查人员甚至不建议使用Optional作为方法参数。

16.总结

在本篇博客中,主要介绍了Java 8 Optional类的大多数重要功能。

主要还简要探讨了为什么选择使用Optional而不是显式的空检查和输入验证的一些原因。

我们主要学习了如何使用get()或orElse()和orElseGet()方法获取Optional或默认值(如果为空)的值(并了解了两者之间的重要区别)。

然后,我们了解了如何使用map(),flatMap()和filter()转换或过滤Optional。

我们看到了流畅的API Optional提供了什么,因为它使我们能够轻松地链接不同的方法。

最后,我们看到了如何使用Optionals作为方法参数是一个坏主意,以及如何避免使用它。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值