zoukankan      html  css  js  c++  java
  • 如何很“礼貌”的避免抛出空指针异常

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

    摘要

    说到空指针,是猿宝宝们最头疼的问题(赞同的评论区“+1”哦),这篇文章教大家如何很“礼貌”的避免抛出空指针异常,大家此时此刻有个疑问,怎么个礼貌发,那么大招来了,大家装备都升级了吧,以免我放大招伤到猿宝宝,哈哈哈,那就是JDK1.8自动新特性Optional,到这里不得不说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作为方法参数是一个坏主意,以及如何避免使用它。

  • 相关阅读:
    2015第18周四
    2015第18周三程序员能力
    2015第18周二
    2015第18周一
    2015第17周日活在当下
    2015第17周六去除表中某字段重复记录
    2015第17周五
    2015第17周四
    Mac OS X Yosemite安装Hadoop 2.6记录
    GLEW_ERROR_NO_GL_VERSION的解决方法
  • 原文地址:https://www.cnblogs.com/MrZhangxd/p/12171710.html
Copyright © 2011-2022 走看看