第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

全部開發(fā)者教程

Optional 類

上一小節(jié),我們接觸到了Optional類,但沒有詳細(xì)展開介紹,Optional類也是 Java 8 新加入的類。本小節(jié)我們就來學(xué)習(xí)一下這個(gè)類,你將了解到Optional類的解決了什么問題,如何創(chuàng)建Optioanl類的對(duì)象,它又有哪些常用方法,如何在實(shí)際開發(fā)中應(yīng)用Optional類等內(nèi)容。

1. Optional 類概述

空指針異常(NullPointerExceptions)是 Java 最常見的異常之一,一直以來都困擾著 Java 程序員。一方面,程序員不得不在代碼中寫很多null的檢查邏輯,讓代碼看起來非常臃腫;另一方面,由于其屬于運(yùn)行時(shí)異常,是非常難以預(yù)判的。

為了預(yù)防空指針異常,GoogleGuava項(xiàng)目率先引入了Optional類,通過使用檢查空值的方式來防止代碼污染,受到Guava項(xiàng)目的啟發(fā),隨后在Java 8中也引入了Optional類。

Optional 類位于java.util包下,是一個(gè)可以為 null容器對(duì)象,如果值存在則isPresent()方法會(huì)返回 true ,調(diào)用 get() 方法會(huì)返回該對(duì)象,可以有效避免空指針異常。下面我們來學(xué)習(xí)如何實(shí)例化這個(gè)類,以及這個(gè)類下提供了哪些常用方法。

2. 創(chuàng)建 Optional 對(duì)象

查看 java.util.Optional類源碼,可以發(fā)現(xiàn)其構(gòu)造方法是私有的,因此不能通過new關(guān)鍵字來實(shí)例化:

我們可以通過如下幾種方法,來創(chuàng)建Optional 對(duì)象:

  • Optional.of(T t):創(chuàng)建一個(gè) Optional 對(duì)象,參數(shù) t 必須非空;
  • Optional.empty():創(chuàng)建一個(gè)空的Optional實(shí)例;
  • Optional.ofNullable(T t):創(chuàng)建一個(gè)Optional對(duì)象,參數(shù)t 可以為 null。

實(shí)例如下:

實(shí)例演示
預(yù)覽 復(fù)制
復(fù)制成功!
import java.util.Optional;

public class OptionalDemo1 {

    public static void main(String[] args) {
        // 創(chuàng)建一個(gè) StringBuilder 對(duì)象
        StringBuilder string = new StringBuilder("我是一個(gè)字符串");
        
        // 使用 Optional.of(T t) 方法,創(chuàng)建 Optional 對(duì)象,注意 T 不能為空:
        Optional<StringBuilder> stringBuilderOptional = Optional.of(string);
        System.out.println(stringBuilderOptional);

        // 使用 Optional.empty() 方法,創(chuàng)建一個(gè)空的 Optional 對(duì)象:
        Optional<Object> empty = Optional.empty();
        System.out.println(empty);

        // 使用 Optional.ofNullable(T t) 方法,創(chuàng)建 Optional 對(duì)象,注意 t 允許為空:
        stringBuilderOptional = null;
        Optional<Optional<StringBuilder>> stringBuilderOptional1 = Optional.ofNullable(stringBuilderOptional);
        System.out.println(stringBuilderOptional1);
    }

}
運(yùn)行案例 點(diǎn)擊 "運(yùn)行案例" 可查看在線運(yùn)行效果

運(yùn)行結(jié)果:

Optional[我是一個(gè)字符串]
Optional.empty
Optional.empty

3. 常用方法

Optional<T>類提供了如下常用方法:

  • booean isPresent():判斷是否包換對(duì)象;
  • void ifPresent(Consumer<? super T> consumer):如果有值,就執(zhí)行 Consumer 接口的實(shí)現(xiàn)代碼,并且該值會(huì)作為參數(shù)傳遞給它;
  • T get():如果調(diào)用對(duì)象包含值,返回該值,否則拋出異常;
  • T orElse(T other):如果有值則將其返回,否則返回指定的other 對(duì)象;
  • T orElseGet(Supplier<? extends T other>):如果有值則將其返回,否則返回由Supplier接口實(shí)現(xiàn)提供的對(duì)象;
  • T orElseThrow(Supplier<? extends X> exceptionSupplier):如果有值則將其返回,否則拋出由Supplier接口實(shí)現(xiàn)提供的異常。

知道了如何創(chuàng)建Optional對(duì)象和常用方法,我們下面結(jié)合具體實(shí)例來看一下,Optional類是如何避免空指針異常的。

請(qǐng)查看如下實(shí)例,其在運(yùn)行時(shí)會(huì)發(fā)生空指針異常:

實(shí)例演示
預(yù)覽 復(fù)制
復(fù)制成功!
import java.util.Optional;

public class OptionalDemo2 {

    static class Category {
        private String name;

        public Category(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Category{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }

    static class Goods {
        private String name;

        private Category category;

        public Goods() {

        }

        public Goods(String name, Category category) {
            this.name = name;
            this.category = category;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Category getCategory() {
            return category;
        }

        public void setCategory(Category category) {
            this.category = category;
        }

        @Override
        public String toString() {
            return "Good{" +
                    "name='" + name + '\'' +
                    ", category=" + category +
                    '}';
        }
    }

    /**
     * 獲取商品的分類名稱
     * @param goods 商品
     * @return 分類名稱
     */
    static String getGoodsCategoryName(Goods goods) {
        return goods.getCategory().getName();
    }

    public static void main(String[] args) {
        // 實(shí)例化一個(gè)商品類
        Goods goods = new Goods();
        // 獲取商品的分類名稱
        String categoryName = getGoodsCategoryName(goods);
        System.out.println(categoryName);
    }
}
運(yùn)行案例 點(diǎn)擊 "運(yùn)行案例" 可查看在線運(yùn)行效果

運(yùn)行結(jié)果:

Exception in thread "main" java.lang.NullPointerException
	at OptionalDemo2.getGoodsCategoryName(OptionalDemo2.java:73)
	at OptionalDemo2.main(OptionalDemo2.java:80)

實(shí)例中,由于在實(shí)例化Goods類時(shí),我們沒有給其下面的Category類型的屬性category賦值,它就為 null,在運(yùn)行時(shí), null.getName()就會(huì)拋出空指針異常。同理,如果goods實(shí)例為null,那么null.getCategory()也會(huì)拋出空指針異常。

在沒有使用Optional類的情況下,想要優(yōu)化代碼,就不得不改寫getGoodsCategoryName()方法:

static String getGoodsCategoryName(Goods goods) {
    if (goods != null) {
        Category category = goods.getCategory();
        if (category != null) {
            return category.getName();
        }
    }
    return "該商品無分類";
}

這也就是我們上面說的null檢查邏輯代碼,此處有兩層if嵌套,如果有更深層次的級(jí)聯(lián)屬性,就要嵌套更多的層級(jí)。

下面我們將Optional類引入實(shí)例代碼:

實(shí)例演示
預(yù)覽 復(fù)制
復(fù)制成功!
import java.util.Optional;

public class OptionalDemo3 {

    static class Category {
        private String name;

        public Category(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Category{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }

    static class Goods {
        private String name;

        private Category category;

        public Goods() {

        }

        public Goods(String name, Category category) {
            this.name = name;
            this.category = category;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Category getCategory() {
            return category;
        }

        public void setCategory(Category category) {
            this.category = category;
        }

        @Override
        public String toString() {
            return "Good{" +
                    "name='" + name + '\'' +
                    ", category=" + category +
                    '}';
        }
    }

    /**
     * 獲取商品的分類名稱(使用 Optional 類包裝)
     * @param goods 商品
     * @return 分類名稱
     */
    static String getGoodsCategoryName(Goods goods) {
        // 將商品實(shí)例包裝入 Optional 類,創(chuàng)建 Optional<Goods> 對(duì)象
        Optional<Goods> goodsOptional = Optional.ofNullable(goods);
        Goods goods1 = goodsOptional.orElse(new Goods("默認(rèn)商品", new Category("默認(rèn)分類")));
        // 此時(shí) goods1 一定是非空,不會(huì)產(chǎn)生空指針異常
        Category category = goods1.getCategory();

        // 將分類實(shí)例包裝入 Optional 類,創(chuàng)建 Optional<Category> 對(duì)象
        Optional<Category> categoryOptional = Optional.ofNullable(category);
        Category category1 = categoryOptional.orElse(new Category("默認(rèn)分類"));
        // 此時(shí) category1 一定是非空,不會(huì)產(chǎn)生空指針異常
        return category1.getName();
    }

    public static void main(String[] args) {
        // 實(shí)例化一個(gè)商品類
        Goods goods = null;
        // 獲取商品的分類名稱
        String categoryName = getGoodsCategoryName(goods);
        System.out.println(categoryName);
    }
}
運(yùn)行案例 點(diǎn)擊 "運(yùn)行案例" 可查看在線運(yùn)行效果

運(yùn)行結(jié)果:

默認(rèn)分類

實(shí)例中,我們使用Optional類的 ofNullable(T t)方法分別包裝了goods對(duì)象及其級(jí)聯(lián)屬性category對(duì)象,允許對(duì)象為空,然后又調(diào)用了其ofElse(T t)方法保證了對(duì)象一定非空。這樣,空指針異常就被我們優(yōu)雅地規(guī)避掉了。

4. 對(duì)于空指針異常的改進(jìn)

Java 14 對(duì)于空指針異常有了一些改進(jìn),它提供了更明確異常堆棧打印信息,JVM 將精確地確定那個(gè)變量是null,不過空指針異常依然無法避免。明確的異常堆棧信息,能夠幫助開發(fā)者快速定位錯(cuò)誤發(fā)生的位置。

5. 小結(jié)

通過本小節(jié)的學(xué)習(xí),我們知道了 Optional 類主要用于應(yīng)對(duì) Java 中的空指針異常,它是一個(gè)可以為 null 的容器對(duì)象,我們可以通過Optional類下的幾個(gè)靜態(tài)方法來創(chuàng)建對(duì)象。另外,我們也結(jié)合實(shí)例介紹了如何使用Optional類來規(guī)避空指針異常,實(shí)例中還有很多其他沒用到的 API,希望大家可以自己研習(xí)。