Java8特性---關於Null

爲了防止無良網站的爬蟲抓取文章,特此標識,轉載請註明文章出處。LaplaceDemon/SJQ。html

http://www.cnblogs.com/shijiaqi1066/p/5713941.html java

 

 

 

Objects工具類

Objects工具類提供了一些靜態方法,用於支持補充對象的一些基礎操做。該類在Java 1.7被引入,部分方法1.8引入。某些方法對對象檢查null提供必定的支持。express

static <T> int

compare(T a, T b, Comparator<? super T> c)api

該方法用於比較兩個對象。 bash

static boolean

deepEquals(Object a, Object b)oracle

若參數深度相等,則返回true,不然返回false。 app

static boolean

equals(Object a, Object b)less

若是參數相等,則返回true,不然返回false。 ide

static int

hash(Object... values)函數

計算函數參數列表的Hash值。 

static int

hashCode(Object o)

若參數爲null,則返回0。不然返回對象的Hash值。 

static boolean

isNull(Object obj)

若是對象爲null,則返回true;若是對象不爲null,則返回false。

static boolean

nonNull(Object obj)

若是對象不爲null,則返回true;若是對象爲null,則返回false。 

static <T> T

requireNonNull(T obj)

檢查對象不爲null。 

static <T> T

requireNonNull(T obj, String message)

檢查對象不爲null。若爲null,則拋出被定製的過的NullPointerException異常。 

static <T> T

requireNonNull(T obj, Supplier<String> messageSupplier)

檢查對象不爲null。若爲null,則拋出被定製的過的NullPointerException異常。 

static String

toString(Object o)

返回參數的字符串,若是對象爲null,則返回null。

static String

toString(Object o, String nullDefault)

返回參數的字符串,若是對象爲null,則返回第二個參數nullDefault。 

 

 

煩人的NullPointException

Java中常常會遇到這樣的表達式:

String version = computer.getSoundcard().getUSB().getVersion(); 

這種表達式很爽,但若是getSoundcard、getUSB、getVersion可能會返回Null指針,那麼這段代碼就必須這樣寫:

String version = "UNKNOWN";
if(computer != null){
  Soundcard soundcard = computer.getSoundcard();
  if(soundcard != null){
    USB usb = soundcard.getUSB();
    if(usb != null){
      version = usb.getVersion();
    }
  }
}

因此,若是沒法肯定方法返回的對象是非空的,則咱們須要時時刻刻都須要提防調用的方法是否返回null,以防止NullPointerException。

 

 

Optional類

受到Haskell和Scala的啓發,Java8引入了java.util.Optional<T>類。這是一個容器類。該容器只包含一個值,要麼改值存在,要麼不存在。

 

1.建立Optional對象

空的Optional對象

Optional<Soundcard> sc = Optional.empty();

 

 

of 工廠方法

爲非null的值建立一個Optional。Optional對象的構造方法。若是傳入參數爲null,則拋出NullPointerException 。

//調用工廠方法建立Optional實例
Optional<String> name = Optional.of("Sanaulla");
//傳入參數爲null,拋出NullPointerException. Optional<String> someNull = Optional.of(null);

 

ofNullable 工廠方法

爲指定的值建立一個Optional。若值爲null,則返回一個空的Optional。ofNullable與of方法類似,惟一的區別是能夠接受參數爲null的狀況。

//下面建立了一個不包含任何值的Optional實例
//例如,值爲'null'
Optional empty = Optional.ofNullable(null);
 
 

2.Null檢查與相應的處理。

isPresent

若是值存在返回true,不然返回false。

 

get

能夠返回Optional容器裏的對象。若Optional有值則將其返回;若沒有值,拋出NoSuchElementException。

//執行下面的代碼會輸出:No value present
try {
  //在空的Optional實例上調用get(),拋出NoSuchElementException
  System.out.println(empty.get());
} catch (NoSuchElementException ex) {
  System.out.println(ex.getMessage());
}

 

get方法與isPresent方法組合能夠這樣使用:

//isPresent方法用來檢查Optional實例中是否包含值
if (name.isPresent()) {
  //在Optional實例內調用get()返回已存在的值
  System.out.println(name.get());//輸出Sanaulla
}

可是注意,這種組合跟null檢測沒有什麼區別,因此並不提倡這樣使用Optional。

 

ifPresent

若是Optional實例有值則爲其調用從參數傳入consumer,不然不作處理。

要理解ifPresent方法,首先須要瞭解Consumer類。簡答地說,Consumer類包含一個抽象方法。該抽象方法對傳入的值進行處理,但沒有返回值。Java8支持不用接口直接經過lambda表達式傳入參數。

若是Optional實例有值,調用ifPresent()能夠接受接口段或lambda表達式。相似下面的代碼:

//ifPresent方法接受lambda表達式做爲參數。
//lambda表達式對Optional的值調用consumer進行處理。
name.ifPresent((value) -> {
  System.out.println("The length of the value is: " + value.length());
});

 

orElse

若是Optional實例有值則將其返回,不然返回orElse方法傳入的參數。

//若是值不爲null,orElse方法返回Optional實例的值。
//若是爲null,返回傳入的消息。
//輸出:There is no value present!
System.out.println(empty.orElse("There is no value present!"));
//輸出:Sanaulla
System.out.println(name.orElse("There is some value!"));

 

orElseGet

orElseGet與orElse方法相似,區別在於獲得的默認值。orElse方法將傳入的字符串做爲默認值,orElseGet方法能夠接受Supplier接口的實現用來生成默認值。示例以下:

//orElseGet與orElse方法相似,區別在於orElse傳入的是默認值,
//orElseGet能夠接受一個lambda表達式生成默認值。
//輸出:Default Value
System.out.println(empty.orElseGet(() -> "Default Value"));
//輸出:Sanaulla
System.out.println(name.orElseGet(() -> "Default Value"));

 

orElseThrow

若是有值則將其返回,不然拋出supplier接口建立的異常。

在orElseGet方法中,咱們傳入一個Supplier接口。然而,在orElseThrow中咱們能夠傳入一個lambda表達式或方法,若是值不存在來拋出異常。示例以下:

try {
  //orElseThrow與orElse方法相似。與返回默認值不一樣,
  //orElseThrow會拋出lambda表達式或方法生成的異常 
  empty.orElseThrow(ValueAbsentException::new);
} catch (Throwable ex) {
  //輸出: No value present in the Optional instance
  System.out.println(ex.getMessage());
}

ValueAbsentException定義以下:

class ValueAbsentException extends Throwable {
 
  public ValueAbsentException() {
    super();
  }
 
  public ValueAbsentException(String msg) {
    super(msg);
  }
 
  @Override
  public String getMessage() {
    return "No value present in the Optional instance";
  }
}

 

 

map

若是Optional讀寫沒有值,則該方法直接返回空的Optional對象。

若是Optional對象有值,則對其執行調用mapping函數獲得返回值。

若是返回值爲null,則返回空Optional對象。

若是返回值不爲null,則建立包含mapping返回值的Optional做爲map方法返回值。

例:

//map方法執行傳入的lambda表達式參數對Optional實例的值進行修改。
//爲lambda表達式的返回值建立新的Optional實例做爲map方法的返回值。
Optional<String> upperName = name.map((value) -> value.toUpperCase());
System.out.println(upperName.orElse("No value found"));

 

 

flatMap

若是有值,爲其執行mapping函數返回Optional類型返回值,不然返回空Optional。

注意:flatMap方法的mapping函數必須是Optional。

例:

// flatMap與map(Function)很是相似,區別在於傳入方法的lambda表達式的返回類型。
// map方法中的lambda表達式返回值能夠是任意類型,在map函數返回以前會包裝爲Optional。 
// 但flatMap方法中的lambda表達式返回值必須是Optionl實例。
upperName = name.flatMap((value) -> Optional.of(value.toUpperCase()));
System.out.println(upperName.orElse("No value found"));

 

 

辨析flatMap方法與map方法

flatMap方法與map方法相似。

區別在於:

  • map方法的map函數返回值能夠是任何類型T。
  • flatMap方法中的map函數返回值必須是Optional。調用結束時,flatMap不會對結果用Optional封裝。

 

 

filter

該方法經過傳入lambda表達式對Optional實例的值進行過濾。若是有值而且知足斷言條件返回包含該值的Optional,不然返回空Optional。

例:

//filter方法檢查給定的Option值是否知足某些條件。
//若是知足則返回同一個Option實例,不然返回空Optional。
Optional<String> longName = name.filter((value) -> value.length() > 6);
System.out.println(longName.orElse("The name is less than 6 characters"));//輸出Sanaulla
 
//另外一個例子是Optional值不知足filter指定的條件。
Optional<String> anotherName = Optional.of("Sana");
Optional<String> shortName = anotherName.filter((value) -> value.length() > 6);
//輸出:name長度不足6字符
System.out.println(shortName.orElse("The name is less than 6 characters"));

 

總結Optional類的各個方法。如下是一個完整的示例:

public class OptionalDemo {
 
  public static void main(String[] args) {
    //建立Optional實例,也能夠經過方法返回值獲得。
    Optional<String> name = Optional.of("Sanaulla");
 
    //建立沒有值的Optional實例,例如值爲'null'
    Optional empty = Optional.ofNullable(null);
 
    //isPresent方法用來檢查Optional實例是否有值。
    if (name.isPresent()) {
      //調用get()返回Optional值。
      System.out.println(name.get());
    }
 
    try {
      //在Optional實例上調用get()拋出NoSuchElementException。
      System.out.println(empty.get());
    } catch (NoSuchElementException ex) {
      System.out.println(ex.getMessage());
    }
 
    //ifPresent方法接受lambda表達式參數。
    //若是Optional值不爲空,lambda表達式會處理並在其上執行操做。
    name.ifPresent((value) -> {
      System.out.println("The length of the value is: " + value.length());
    });
 
    //若是有值orElse方法會返回Optional實例,不然返回傳入的錯誤信息。
    System.out.println(empty.orElse("There is no value present!"));
    System.out.println(name.orElse("There is some value!"));
 
    //orElseGet與orElse相似,區別在於傳入的默認值。
    //orElseGet接受lambda表達式生成默認值。
    System.out.println(empty.orElseGet(() -> "Default Value"));
    System.out.println(name.orElseGet(() -> "Default Value"));
 
    try {
      //orElseThrow與orElse方法相似,區別在於返回值。
      //orElseThrow拋出由傳入的lambda表達式/方法生成異常。
      empty.orElseThrow(ValueAbsentException::new);
    } catch (Throwable ex) {
      System.out.println(ex.getMessage());
    }
 
    //map方法經過傳入的lambda表達式修改Optonal實例默認值。
    //lambda表達式返回值會包裝爲Optional實例。
    Optional<String> upperName = name.map((value) -> value.toUpperCase());
    System.out.println(upperName.orElse("No value found"));
 
    //flatMap與map(Funtion)很是類似,區別在於lambda表達式的返回值。
    //map方法的lambda表達式返回值能夠是任何類型,可是返回值會包裝成Optional實例。
    //可是flatMap方法的lambda返回值老是Optional類型。
    upperName = name.flatMap((value) -> Optional.of(value.toUpperCase()));
    System.out.println(upperName.orElse("No value found"));
 
    //filter方法檢查Optiona值是否知足給定條件。
    //若是知足返回Optional實例值,不然返回空Optional。
    Optional<String> longName = name.filter((value) -> value.length() > 6);
    System.out.println(longName.orElse("The name is less than 6 characters"));
 
    //另外一個示例,Optional值不知足給定條件。
    Optional<String> anotherName = Optional.of("Sana");
    Optional<String> shortName = anotherName.filter((value) -> value.length() > 6);
    System.out.println(shortName.orElse("The name is less than 6 characters"));
 
  }
 
}

上述代碼輸出以下:

Sanaulla
No value present
The length of the value is: 8
There is no value present!
Sanaulla
Default Value
Sanaulla
No value present in the Optional instance
SANAULLA
SANAULLA
Sanaulla
The name is less than 6 characters

 

 

 

最後,讓咱們解決Null調用這個問題:

String version = computer.getSoundcard().getUSB().getVersion();

 

首先設計的類,類中方法的須要返回Optional對象。

public class Computer {
  private Optional<Soundcard> soundcard;  
  public Optional<Soundcard> getSoundcard() { ... }
  ...
}

public class Soundcard {
  private Optional<USB> usb;
  public Optional<USB> getUSB() { ... }

}

public class USB{
  public String getVersion(){ ... }
}

 

如下是一種錯誤的實例。這段代碼沒法經過編譯。

String version = computer.map(Computer::getSoundcard)
                  .map(Soundcard::getUSB)
                  .map(USB::getVersion)
                  .orElse("UNKNOWN");

首先computer是Optional類型,Optional類型經過Computer:getSoundcard,該方法返回Optional類型,再包裝進map方法,因此最後返回了Optional<Optional<T>>類型,該類型進入到下一個map函數中,參數沒法匹配。因此編譯不過。

使用flatMap方法控制返回類型,以保障鏈式調用。

String version = computer.flatMap(Computer::getSoundcard)
                   .flatMap(Soundcard::getUSB)
                   .map(USB::getVersion)
                   .orElse("UNKNOWN");

 

 

 

 

爲了防止無良網站的爬蟲抓取文章,特此標識,轉載請註明文章出處。LaplaceDemon/SJQ。

http://www.cnblogs.com/shijiaqi1066/p/5713941.html 

相關文章
相關標籤/搜索