欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java Optional解決空指針異??偨Y(jié)(java 8 功能)

 更新時(shí)間:2020年11月24日 11:51:27   作者:趙雍  
這篇文章主要介紹了Java Optional解決空指針異??偨Y(jié)(java 8 功能),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

1、概述

Java8的版本,新增了Optional和[Lambda]表達(dá)式,Optional主要用于作為返回類型(主要解決的問題是臭名昭著的空指針異常

(NullPointerException)),并將其與流(或返回可選的方法)相結(jié)合以構(gòu)建連貫API。
但是,有些情況可以被認(rèn)為是陷阱,因?yàn)樗鼈儠?huì)降低代碼的質(zhì)量,甚至導(dǎo)致意想不到的錯(cuò)誤??偨Y(jié)以下26個(gè)例子,以避免這些陷阱。

2、 目 錄

[第1項(xiàng):決不將Null分配給可選變量]

[第2項(xiàng):調(diào)用Optional.get()之前,確保Optional具有值]

[第3項(xiàng):當(dāng)不存在任何值時(shí),通過Optional.orElse()方法設(shè)置/返回已經(jīng)構(gòu)造的默認(rèn)對(duì)象]

[第4項(xiàng):不存在任何值時(shí),通過Optional.orElseGet()方法設(shè)置/返回不存在的默認(rèn)對(duì)象]

[第5項(xiàng):當(dāng)不存在任何值時(shí),自Java 10起通過orElseThrow()拋出java.util.NoSuchElementException異常]

[第6項(xiàng):當(dāng)不存在任何值時(shí),通過orElseThrow(Supplier <?extended X> exceptionSupplier)引發(fā)顯式異常]

[第7項(xiàng):當(dāng)你有可選的并且需要空引用時(shí),請(qǐng)使用orElse(null)]

[第8項(xiàng):使用可選(如果存在)。如果不存在,則什么也不做。這是Optional.ifPresent()的工作。]

[第9項(xiàng):使用可選(如果存在)。如果不存在,請(qǐng)執(zhí)行基于空的操作。這是Optional.ifPresentElse(),Java 9的工作。]

[第10項(xiàng):當(dāng)值存在時(shí),設(shè)置/返回該可選項(xiàng)。如果不存在任何值,則設(shè)置/返回另一個(gè)可選項(xiàng)。這是Java 9的Optional.or()的工作。]

[第11項(xiàng):Optional.orElse / orElseXXX是Lambdas中的isPresent()-get()完美替代]

[第12項(xiàng):避免僅出于獲取價(jià)值的目的而鏈接可選方法]

[第13項(xiàng):不要聲明任何類型的可選字段]

[第14項(xiàng):在構(gòu)造函數(shù)參數(shù)中不要使用可選]

[第15項(xiàng):在Setters參數(shù)中不要使用可選]

[第16項(xiàng):在方法參數(shù)中不要使用可選]

[第17項(xiàng):不要使用Optional 的返回空的集合或數(shù)組]

[第18項(xiàng):避免在集合中使用Optional]

[第19項(xiàng):不要混淆Optional.of()和Optional.ofNullable()]

[第20項(xiàng):避免使用可選的,并選擇非通用的OptionalInt,OptionalLong或OptionalDouble]

[第21項(xiàng):無需包裝主張平等的任擇方案]

[第22項(xiàng):通過Map()和flatMap()轉(zhuǎn)換值]

[第23項(xiàng):使用filter()根據(jù)預(yù)定義的規(guī)則拒絕包裝值]

[第24項(xiàng):我們是否需要將可選API與流API鏈接在一起?]

[第25項(xiàng):避免對(duì)可選選項(xiàng)使用身份敏感的操作]

[第26項(xiàng):如果Optional為空,則返回一個(gè)布爾值。首選Java 11,Optional.isEmpty()]

第1項(xiàng):決不將Null分配給可選變量

避免:

// 避免

public Optional<Cart> fetchCart() {

 Optional<Cart> emptyCart = null;

 ...

}

首選:

// 首選

public Optional<Cart> fetchCart() {

 Optional<Cart> emptyCart = Optional.empty();

 ...

}

首選Optional.empty()初始化 Optional而不是null值。Optional只是一個(gè)容器/盒子,用初始化它是沒有意義的null。

第2項(xiàng):調(diào)用Optional.get()之前,確保Optional具有值

如果出于某種原因你決定使用Optional.get(),那么請(qǐng)不要忘記必須Optional在此調(diào)用之前證明該值存在。通常,將通過基于該Optional.isPresent()方法添加檢查(條件)來執(zhí)行此操作。Optional.get()在某些時(shí)候容易被棄用。

避免:

// 避免

Optional<Cart> cart = ... ; // 這很容易是空的

...

// 如果“cart”是空的,那么這段代碼將拋出一個(gè)java.util.NoSuchElementException

Cart myCart = cart.get();

首選:

// 首選

if (cart.isPresent()) {

  Cart myCart = cart.get();

  ...

} else {

  ... // 做一些不調(diào)用carter .get()的事情

}

第3項(xiàng):當(dāng)不存在任何值時(shí),通過Optional.orElse()方法設(shè)置/返回已經(jīng)構(gòu)造的默認(rèn)對(duì)象

使用Optional.orElse()方法代表了用于設(shè)置/返回值的isPresent()-get()對(duì)的優(yōu)雅替代。這里重要的一點(diǎn)是,即使是非空可選的,也要計(jì)算oforElse()參數(shù)。這意味著即使不使用它,也會(huì)對(duì)它進(jìn)行評(píng)估,這是一種性能損失。在這個(gè)上下文中,useorElse()只在參數(shù)(默認(rèn)對(duì)象)已經(jīng)構(gòu)造完成時(shí)才使用。在其他情況下,請(qǐng)依賴第4項(xiàng)。

避免:

// 避免

public static final String USER_STATUS = "UNKNOWN";

...

public String findUserStatus(long id) {

  Optional<String> status = ... ; // 容易返回一個(gè)空的 Optional

  if (status.isPresent()) {

    return status.get();

  } else {

    return USER_STATUS;

  }

}

首選:

// 首選

public static final String USER_STATUS = "UNKNOWN";

...

public String findUserStatus(long id) {

  Optional<String> status = ... ; // 容易返回一個(gè)空的 Optional

  return status.orElse(USER_STATUS);

}

第4項(xiàng):不存在任何值時(shí),通過Optional.orElseGet()方法設(shè)置/返回不存在的默認(rèn)對(duì)象

使用theOptional.orElseGet()方法表示另一種用于設(shè)置/返回值的替代theisPresent()-get()對(duì)的優(yōu)雅方法。這里重要的一點(diǎn)是,參數(shù)oforElseGet()是Java 8新特性。這意味著作為參數(shù)傳遞的Suppliermethod只在Optionalvalue不存在時(shí)執(zhí)行。因此,這有助于避免創(chuàng)建對(duì)象和執(zhí)行在出現(xiàn)Optionalvalue時(shí)不需要的代碼時(shí)的orElse()性能損失。

避免:

// 避免

public String computeStatus() {

  ... // 一些用來計(jì)算狀態(tài)的代碼

}

public String findUserStatus(long id) {

  Optional<String> status = ... ; // 容易返回一個(gè)空的 Optional

  if (status.isPresent()) {

    return status.get();

  } else {

    return computeStatus();

  }

}

另外,請(qǐng)避免:

// 避免

public String computeStatus() {

  ... // 一些用來計(jì)算狀態(tài)的代碼

}

public String findUserStatus(long id) {

  Optional<String> status = ... ; // 容易返回一個(gè)空的 Optional

  // 即使“status”不是空的,也會(huì)調(diào)用computeStatus()

  return status.orElse(computeStatus());

}

首選:

public String computeStatus() {

  ... // some code used to compute status

}

public String findUserStatus(long id) {

  Optional<String> status = ... ; // 容易返回一個(gè)空的 Optional

  // 僅當(dāng)“status”為空時(shí)才調(diào)用computeStatus()

  return status.orElseGet(this::computeStatus);

}

第5項(xiàng):當(dāng)不存在任何值時(shí),自Java 10起通過orElseThrow()拋出java.util.NoSuchElementException異常

使用該Optional.orElseThrow()方法代表了該方法的另一種優(yōu)雅替代方法isPresent()-get()。有時(shí),當(dāng)Optional不存在值時(shí),你要做的就是拋出java.util.NoSuchElementException異常。從Java 10開始,這可以通過orElseThrow()不帶參數(shù)的方法來完成。對(duì)于Java 8和9,請(qǐng)考慮第6項(xiàng)。

避免:

public String findUserStatus(long id) {

  Optional<String> status = ... ; // 容易返回一個(gè)空的 Optional

  if (status.isPresent()) {

    return status.get();

  } else {

    throw new NoSuchElementException();    

  }

}

首選:

public String findUserStatus(long id) {

  Optional<String> status = ... ; // 容易返回一個(gè)空的 Optional

  return status.orElseThrow();

}

第6項(xiàng):當(dāng)不存在任何值時(shí),通過orElseThrow(Supplier <?extended X> exceptionSupplier)引發(fā)顯式異常

在Java 10中,對(duì)于 java.util.NoSuchElementException,請(qǐng)使用 orElseThrow(),如第5項(xiàng)所示。使用該Optional.orElseThrow(Supplier&lt;? extends X&gt; exceptionSupplier)方法代表了該方法的另一種優(yōu)雅替代方法isPresent()-get()。有時(shí),當(dāng)Optional不存在值時(shí),你要做的就是拋出一個(gè)明確的異常。從Java 10開始,如果該異常java.util.NoSuchElementException僅依賴于orElseThrow()不帶參數(shù)的方法-第5項(xiàng)。

避免:

public String findUserStatus(long id) {

  Optional<String> status = ... ; // 容易返回一個(gè)空的 Optional

  if (status.isPresent()) {

    return status.get();

  } else {

    throw new IllegalStateException();

  }

}

首選:

public String findUserStatus(long id) {

  Optional<String> status = ... ; // 容易返回一個(gè)空的 Optional

  return status.orElseThrow(IllegalStateException::new);

}

第7項(xiàng):當(dāng)您有可選的并且需要空引用時(shí),請(qǐng)使用orElse(null)

如果你有Optional需要提供null參考的,請(qǐng)使用 orElse(null)。否則,請(qǐng)避免 orElse(null)。orElse(null)當(dāng)我們有一個(gè)Optional,并且需要null在某些情況下調(diào)用一個(gè)接受引用的方法時(shí),就會(huì)發(fā)生典型的使用情況。例如,讓我們看一下Method.invoke()Java Reflection API。此方法的第一個(gè)參數(shù)是要在其上調(diào)用此特定方法的對(duì)象實(shí)例。如果方法是static,第一個(gè)參數(shù),則應(yīng)為null。

避免:

Method myMethod = ... ;

...

// 包含MyClass的實(shí)例,如果“myMethod”是靜態(tài)的,則為空

Optional<MyClass> instanceMyClass = ... ;

...

if (instanceMyClass.isPresent()) {

  myMethod.invoke(instanceMyClass.get(), ...); 

} else {

  myMethod.invoke(null, ...); 

}

首選:

Method myMethod = ... ;

...

// 包含MyClass的實(shí)例,如果“myMethod”是靜態(tài)的,則為空

Optional<MyClass> instanceMyClass = ... ;

...

myMethod.invoke(instanceMyClass.orElse(null), ...);

第8項(xiàng):使用可選(如果存在)。如果不存在,則什么也不做。這是Optional.ifPresent()的工作。

當(dāng)你只需要使用值時(shí),Optional.ifPresent()是isPresent()-get()paid的不錯(cuò)選擇。 如果沒有值,則不執(zhí)行任何操作。

避免:

Optional<String> status = ... ;

...

if (status.isPresent()) {

  System.out.println("Status: " + status.get());

}

首選:

Optional<String> status ... ;

...

status.ifPresent(System.out::println);

第9項(xiàng):使用可選(如果存在)。如果不存在,請(qǐng)執(zhí)行基于空的操作。這是Optional.ifPresentElse(),Java 9的工作。

從Java 9開始,它Optional.ifPresentOrElse()是isPresent()-get()配對(duì)的不錯(cuò)選擇。這與ifPresent()方法類似, 只不過它也覆蓋else分支。

避免:

Optional<String> status = ... ;

if(status.isPresent()) {

  System.out.println("Status: " + status.get());

} else {

  System.out.println("Status not found");

}

首選:

Optional<String> status = ... ;

status.ifPresentOrElse(

  System.out::println,

  () -> System.out.println("Status not found")

);

第10項(xiàng):當(dāng)值存在時(shí),設(shè)置/返回該可選項(xiàng)。如果不存在任何值,則設(shè)置/返回另一個(gè)可選項(xiàng)。這是Java 9的Optional.or()的工作。

有時(shí),對(duì)于非空, Optional,我們想設(shè)置/返回那個(gè) Optional。當(dāng)我們Optional為空時(shí),我們想執(zhí)行其他操作,該操作也返回一個(gè) Optional。該orElse()和orElseGet()方法不能做到這一點(diǎn),因?yàn)閮烧叨紝⒎祷卣归_值?,F(xiàn)在該介紹Java 9 Optional.or()方法了,該方法能夠返回Optional描述值。否則,它將返回Optional提供功能產(chǎn)生的結(jié)果。

避免:

public Optional<String> fetchStatus() {

  Optional<String> status = ... ;

  Optional<String> defaultStatus = Optional.of("PENDING");

  if (status.isPresent()) {

    return status;

  } else {

    return defaultStatus;

  } 

}

另外,請(qǐng)避免:

public Optional<String> fetchStatus() {

  Optional<String> status = ... ;

  return status.orElseGet(() -> Optional.<String>of("PENDING"));

}

首選:

public Optional<String> fetchStatus() {

  Optional<String> status = ... ;

  Optional<String> defaultStatus = Optional.of("PENDING");

  return status.or(() -> defaultStatus);

  // 或者,不定義“defaultStatus”

  return status.or(() -> Optional.of("PENDING"));

}

第11項(xiàng):Optional.orElse / orElseXXX是Lambdas中的isPresent()-get()完美替代

這可用于獲取鏈接的lambda,而不是被破壞的代碼??紤] ifPresent() 和 ifPresentOrElse() Java中9或 or() Java中9的方法,也是如此。某些特定于lambda的操作正在返回Optional(例如,findFirst(), findAny(), reduce(),...)。嘗試Optional通過該isPresent()-get()對(duì)使用此方法是一種笨拙的方法,因?yàn)樗赡苄枰蚱苐ambda鏈,用if語句污染代碼,并考慮繼續(xù)使用鏈。在這種情況下,orElse()and和orElseXXX()非常方便,因?yàn)樗鼈兛梢灾苯釉趌ambda表達(dá)式鏈中鏈接,并避免破壞代碼。

例子1

避免:

List<Product> products = ... ;

Optional<Product> product = products.stream()

  .filter(p -> p.getPrice() < price)

  .findFirst();

if (product.isPresent()) {

  return product.get().getName();

} else {

  return "NOT FOUND";

}

另外,請(qǐng)避免:

List<Product> products = ... ;

Optional<Product> product = products.stream()

  .filter(p -> p.getPrice() < price)

  .findFirst();

return product.map(Product::getName)

  .orElse("NOT FOUND");

首選:

List<Product> products = ... ;

return products.stream()

  .filter(p -> p.getPrice() < price)

  .findFirst()

  .map(Product::getName)

  .orElse("NOT FOUND");

例子2

避免:

Optional<Cart> cart = ... ;

Product product = ... ;

...

if(!cart.isPresent() ||

  !cart.get().getItems().contains(product)) {

  throw new NoSuchElementException();

}

首選:

Optional<Cart> cart = ... ;

Product product = ... ;

...

cart.filter(c -> c.getItems().contains(product)).orElseThrow();

第12項(xiàng):避免僅出于獲取價(jià)值的目的而鏈接可選方法

有時(shí),我們傾向于“過度使用”事物。意味著我們有一個(gè)東西,例如 Optional,并且到處都可以看到用例。在的情況下 Optional,常見的情況是出于獲得價(jià)值的單一目的而鏈接其方法。避免這種做法,而是依靠簡單明了的代碼。

避免:

public String fetchStatus() {

  String status = ... ;

  return Optional.ofNullable(status).orElse("PENDING");

}

首選:

public String fetchStatus() {

  String status = ... ;

  return status == null ? "PENDING" : status;

}

第13項(xiàng):不要聲明任何類型的可選字段

請(qǐng)勿 Optional 在方法(包括 setters)或構(gòu)造函數(shù)參數(shù)中使用。

請(qǐng)記住,這Optional 并不是要用于字段,并且不會(huì)實(shí)現(xiàn)Serializable。該Optional班是明確不打算用作一個(gè)Java Bean的屬性。

避免:

public class Customer {

  [access_modifier] [static] [final] Optional<String> zip;

  [access_modifier] [static] [final] Optional<String> zip = Optional.empty();

  ...
}

首選:

public class Customer {

  [access_modifier] [static] [final] String zip;

  [access_modifier] [static] [final] String zip = "";

  ...

}

第14項(xiàng):在構(gòu)造函數(shù)參數(shù)中不要使用可選

請(qǐng)勿將其 Optional 用作字段或方法(包括 setters)的參數(shù)。

這是違背Optional意圖的另一種用法。 Optional用另一種抽象級(jí)別包裝對(duì)象,在這種情況下,只需添加額外的樣板代碼。

避免:

public class Customer {

  private final String name;        // 不可能為null

  private final Optional<String> postcode; //可能為null

  public Customer(String name, Optional<String> postcode) {

    this.name = Objects.requireNonNull(name, () -> "名稱不能為空");

    this.postcode = postcode;

  }

  public Optional<String> getPostcode() {

    return postcode;

  }

  ...
}

首選:

public class Customer {

  private final String name;  

  private final String postcode;

  public Cart(String name, String postcode) {

    this.name = Objects.requireNonNull(name, () -> "名稱不能為空");

    this.postcode = postcode;

  }

  public Optional<String> getPostcode() {

    return Optional.ofNullable(postcode);

  }

  ...
}

如你所見,getter現(xiàn)在返回 Optional。不要以這個(gè)示例作為轉(zhuǎn)換所有此類getter的規(guī)則。多數(shù)情況下,getter返回集合或數(shù)組,在這種情況下,他們更喜歡返回空集合/數(shù)組而不是 Optional。

我認(rèn)為,通常將其用作獲取方法的返回值肯定會(huì)過度使用。

第15項(xiàng):在Setters參數(shù)中不要使用可選

Optional 不能用作Java Bean的屬性或持久屬性類型。 Optional 不是Serializable。Optional在二傳手中使用是另一種反模式。通常,我看到它用作持久屬性類型(將實(shí)體屬性映射為 Optional)。但是,可以O(shè)ptional在域模型實(shí)體中使用,如以下示例所示。

避免:

@Entity

public class Customer implements Serializable {

  private static final long serialVersionUID = 1L;

  ...

  @Column(name="customer_zip")

  private Optional<String> postcode; // optional 字段, 因此可能為空

   public Optional<String> getPostcode() {

    return postcode;

   }

   public void setPostcode(Optional<String> postcode) {

    this.postcode = postcode;

   }

   ...

}

首選:

@Entity

public class Customer implements Serializable {

  private static final long serialVersionUID = 1L;

  ...

  @Column(name="customer_zip")

  private String postcode;

  public Optional<String> getPostcode() {

   return Optional.ofNullable(postcode);

  }

  public void setPostcode(String postcode) {

    this.postcode = postcode;

  }

  ...

}

第16項(xiàng):在方法參數(shù)中不要使用可選

不要 Optional 用作字段或設(shè)置器和構(gòu)造函數(shù)的參數(shù)。Optional在in方法中使用參數(shù)是另一個(gè)常見錯(cuò)誤。這將導(dǎo)致不必要的復(fù)雜代碼。負(fù)責(zé)檢查參數(shù),而不是強(qiáng)制調(diào)用站點(diǎn)創(chuàng)建 Optional。這種做法會(huì)使代碼混亂,并可能導(dǎo)致依賴性。隨著時(shí)間的流逝,您將在所有地方使用它。請(qǐng)記住,這Optional只是另一個(gè)對(duì)象(容器),而且價(jià)它消耗的內(nèi)存是強(qiáng)引用的4倍!但是,你可以用,視情況而定。

避免:

public void renderCustomer(Cart cart, Optional<Renderer> renderer,

              Optional<String> name) {  

  if (cart == null) {

    throw new IllegalArgumentException("Cart不能為空");

  }

  Renderer customerRenderer = renderer.orElseThrow(

    () -> new IllegalArgumentException("Renderer 不能為空")

  );  

  String customerName = name.orElseGet(() -> "anonymous");

  ...

}

//調(diào)用這個(gè)是錯(cuò)誤的

renderCustomer(cart, Optional.<Renderer>of(CoolRenderer::new), Optional.empty());

首選:

public void renderCustomer(Cart cart, Renderer renderer, String name) {

  if (cart == null) {

    throw new IllegalArgumentException("Cart 不能為空");

  }

  if (renderer == null) {

    throw new IllegalArgumentException("Renderer 不能為空");

  }

  String customerName = Objects.requireNonNullElseGet(name, () -> "anonymous");

  ...

}

// 調(diào)用這個(gè)方法

renderCustomer(cart, new CoolRenderer(), null);

另外,更喜歡(依靠NullPointerException):

public void renderCustomer(Cart cart, Renderer renderer, String name) {

  Objects.requireNonNull(cart, "Cart 不能為空");    

  Objects.requireNonNull(renderer, "Renderer 不能為空");    

  String customerName = Objects.requireNonNullElseGet(name, () -> "anonymous");

  ...

}

// 調(diào)用這個(gè)方法

renderCustomer(cart, new CoolRenderer(), null);

另外,更喜歡(避免NullPointerException和使用IllegalArgumentException或其他異常):

public final class MyObjects {

  private MyObjects() {

    throw new AssertionError("Cannot create instances for you!");

  }

  public static <T, X extends Throwable> T requireNotNullOrElseThrow(T obj,

    Supplier<? extends X> exceptionSupplier) throws X {   

    if (obj != null) {

      return obj;

    } else {

      throw exceptionSupplier.get();

    }

  }

}

public void renderCustomer(Cart cart, Renderer renderer, String name) {

  MyObjects.requireNotNullOrElseThrow(cart,

        () -> new IllegalArgumentException("Cart cannot be null"));

  MyObjects.requireNotNullOrElseThrow(renderer,

        () -> new IllegalArgumentException("Renderer cannot be null"));  

  String customerName = Objects.requireNonNullElseGet(name, () -> "anonymous");

  ...

}

// 調(diào)用這個(gè)方法

renderCustomer(cart, new CoolRenderer(), null)

第17項(xiàng):不要使用Optional 的返回空的集合或數(shù)組

支持返回一個(gè)空的集合/數(shù)組??紤]到這一點(diǎn),依靠 Collections.emptyList(), emptyMap()和emptySet()。

為了保持代碼的清潔,輕便避免返回Optional的null或空的集合/數(shù)組。最好返回一個(gè)空數(shù)組或集合。

避免:

public Optional<List<String>> fetchCartItems(long id) {

  Cart cart = ... ;  

  List<String> items = cart.getItems(); //這個(gè)可能會(huì)返回null

  return Optional.ofNullable(items);

}

首選:

public List<String> fetchCartItems(long id) {

  Cart cart = ... ;  

  List<String> items = cart.getItems(); // 這個(gè)可能會(huì)返回null

  return items == null ? Collections.emptyList() : items;

}

第18項(xiàng):避免在集合中使用Optional

見示例

避免:

Map<String, Optional<String>> items = new HashMap<>();

items.put("I1", Optional.ofNullable(...));

items.put("I2", Optional.ofNullable(...));

...

Optional<String> item = items.get("I1");

if (item == null) {

  System.out.println("找不到這把鑰匙");

} else {

  String unwrappedItem = item.orElse("NOT FOUND");

  System.out.println("Key found, Item: " + unwrappedItem);

}

首選(Java 8):

Map<String, String> items = new HashMap<>();

items.put("I1", "Shoes");

items.put("I2", null);

...

// get an item

String item = get(items, "I1"); // Shoes

String item = get(items, "I2"); // null

String item = get(items, "I3"); // NOT FOUND

private static String get(Map<String, String> map, String key) {

 return map.getOrDefault(key, "NOT FOUND");

}

還可以依賴其他方法,例如:

  • containsKey()方法
  • 通過擴(kuò)展實(shí)現(xiàn)簡單HashMap
  • Java 8 computeIfAbsent()方法
  • Apache CommonsDefaultedMap

通過將此示例外推到其他集合,我們可以得出結(jié)論,總有比Optional在集合中使用更好的解決方案。

而且,甚至更糟:

Map<Optional<String>, String> items = new HashMap<>();

Map<Optional<String>, Optional<String>> items = new HashMap<>();

第19項(xiàng):不要混淆Optional.of()和Optional.ofNullable()

混淆或錯(cuò)誤地使用 Optional.of而不是Optional.ofNullable,反之亦然,可能會(huì)導(dǎo)致令人不快的問題。作為此處的關(guān)鍵,請(qǐng)記住Optional.of(null)會(huì)拋出NullPointerException,而Optional.ofNullable(null)會(huì)導(dǎo)致 Optional.empty。

使用Optional.of代替Optional.ofNullable示例

避免:

// AVOID

public Optional<String> fetchItemName(long id) {

  String itemName = ... ; // 這可能導(dǎo)致null

  ...

  return Optional.of(itemName); // 如果“itemName”為空,則拋出NPE :(

}

首選:

public Optional<String> fetchItemName(long id) {

  String itemName = ... ; // 這可能導(dǎo)致null

  ...

  return Optional.ofNullable(itemName); // 沒有NPE風(fēng)險(xiǎn) 

}

使用Optional.ofNullable代替Optional.of示例

避免:

return Optional.ofNullable("PENDING"); // ofNullable不會(huì)增加任何值

首選:

return Optional.of("PENDING"); // 沒有 NPE 風(fēng)險(xiǎn)

第20項(xiàng):避免使用可選的<T>,并選擇非通用的OptionalInt,OptionalLong或OptionalDouble

除非你有盒裝原語,避免特定需求 Optional&lt; T &gt; ,并選擇非通用 OptionalInt, OptionalLong或OptionalDouble。

裝箱和拆箱是昂貴的操作,容易導(dǎo)致性能下降。為了消除這種風(fēng)險(xiǎn),我們可以依靠 OptionalInt,OptionalLong 和OptionalDouble。這些是基本類型的包裝int,long,和double。

避免使用(僅在需要裝箱的原語時(shí)使用):

Optional<Integer> price = Optional.of(50);

Optional<Long> price = Optional.of(50L);

Optional<Double> price = Optional.of(50.43d);

首選:

OptionalInt price = OptionalInt.of(50);      // 打開通過 getAsInt()

OptionalLong price = OptionalLong.of(50L);    // 打開通過 getAsLong()

OptionalDouble price = OptionalDouble.of(50.43d); // 打開通過 getAsDouble()

第21項(xiàng):無需包裝主張平等的任擇方案

有兩個(gè)Optionals在assertEquals()不需要解開值。這是適用的,因?yàn)镺ptional#equals()比較包裝的值,而不是Optional對(duì)象。

Optional.equals()源代碼:

@Override

public boolean equals(Object obj) {

  if (this == obj) {

    return true;

  }

  if (!(obj instanceof Optional)) {

    return false;

  }

  Optional<?> other = (Optional<?>) obj;

  return Objects.equals(value, other.value);

}

避免:

Optional<String> actualItem = Optional.of("Shoes");

Optional<String> expectedItem = Optional.of("Shoes");    

assertEquals(expectedItem.get(), actualItem.get());

首選:

Optional<String> actualItem = Optional.of("Shoes");

Optional<String> expectedItem = Optional.of("Shoes");    

assertEquals(expectedItem, actualItem);

第22項(xiàng):通過Map()和flatMap()轉(zhuǎn)換值

的Optional.map()和Optional.flatMap()是用于將非常方便的辦法Optional值。該map()方法將函數(shù)參數(shù)應(yīng)用于值,然后返回包裝在中的結(jié)果 Optional,而通過比較,該flatMap()方法采用應(yīng)用于值的函數(shù)參數(shù),Optional然后直接返回結(jié)果。

使用 map()
例子1

避免:

Optional<String> lowername ...; // 可能是空的

// transform name to upper case

Optional<String> uppername;

if (lowername.isPresent()) {

  uppername = Optional.of(lowername.get().toUpperCase());

} else {

  uppername = Optional.empty();

}

首選:

Optional<String> lowername ...; // 可能是空的

// 將名稱轉(zhuǎn)換為大寫

Optional<String> uppername = lowername.map(String::toUpperCase);

例子2

避免:

List<Product> products = ... ;

Optional<Product> product = products.stream()

  .filter(p -> p.getPrice() < 50)

  .findFirst();

String name;

if (product.isPresent()) {

  name = product.get().getName().toUpperCase();

} else {

  name = "NOT FOUND";

}

//getName()返回一個(gè)非空字符串

public String getName() {

  return name;

}

首選:

List<Product> products = ... ;

String name = products.stream()

  .filter(p -> p.getPrice() < 50)

  .findFirst()

  .map(Product::getName)

  .map(String::toUpperCase)

  .orElse("NOT FOUND");

// getName()返回一個(gè)字符串

public String getName() {

  return name;

}

使用 flatMap()

避免:

List<Product> products = ... ;

Optional<Product> product = products.stream()

  .filter(p -> p.getPrice() < 50)

  .findFirst();

String name = null;

if (product.isPresent()) {

  name = product.get().getName().orElse("NOT FOUND").toUpperCase();

}

// getName() return Optional

public Optional<String> getName() {

  return Optional.ofNullable(name);

}

首選:

List<Product> products = ... ;

String name = products.stream()

  .filter(p -> p.getPrice() < 50)

  .findFirst()

  .flatMap(Product::getName)

  .map(String::toUpperCase)

  .orElse("NOT FOUND");

// getName() return Optional

public Optional<String> getName() {

  return Optional.ofNullable(name);

}

第23項(xiàng):使用filter()根據(jù)預(yù)定義的規(guī)則拒絕包裝值

傳遞謂詞(條件)作為參數(shù)并獲取一個(gè) Optional 對(duì)象。Optional 如果滿足條件,則使用首字母縮寫;如果不滿足條件,則使用空白 字母 Optional 。使用filter()接受或拒絕包裝的值是一種非常方便的方法,因?yàn)闊o需顯式包裝值就可以實(shí)現(xiàn)它。

避免:

public boolean validatePasswordLength(User userId) {

  Optional<String> password = ...; // User password

  if (password.isPresent()) {

    return password.get().length() > 5;

  }

  return false;

}

首選:

public boolean validatePasswordLength(User userId) {

  Optional<String> password = ...; // User password

  return password.filter((p) -> p.length() > 5).isPresent();

}

第24項(xiàng):我們是否需要將可選API與流API鏈接在一起?

如果是這樣,則我們使用該 Optional.stream() 方法。從Java 9開始,我們可以通過應(yīng)用方法將Optional實(shí)例視為。當(dāng)您需要將Optional API與Stream API鏈接在一起時(shí),這很有用。此方法創(chuàng)建一個(gè)元素或一個(gè)空元素(如果不存在)。此外,我們可以使用Stream API中可用的所有方法。 Stream``Optional.stream()``Stream``Stream``Optional

避免:

public List<Product> getProductList(List<String> productId) {

  return productId.stream()

    .map(this::fetchProductById)

    .filter(Optional::isPresent)

    .map(Optional::get)

    .collect(toList());

}

public Optional<Product> fetchProductById(String id) {

  return Optional.ofNullable(...);

}

首選:

public List<Product> getProductList(List<String> productId) {

  return productId.stream()

    .map(this::fetchProductById)

    .flatMap(Optional::stream)

    .collect(toList());

}

public Optional<Product> fetchProductById(String id) {

  return Optional.ofNullable(...);

}

實(shí)際上,Optional.stream()讓我們來代替filter()和 map()用 flatMap()。

另外,我們可以轉(zhuǎn)換Optional為List:

public static <T> List<T> convertOptionalToList(Optional<T> optional) {

  return optional.stream().collect(toList());

}

第25項(xiàng):避免對(duì)可選選項(xiàng)使用身份敏感的操作

這包括引用相等(==),基于身份哈?;蛲?。Optional類是一個(gè)基于價(jià)值的類作為 LocalDateTime。

避免:

Product product = new Product();

Optional<Product> op1 = Optional.of(product);

Optional<Product> op2 = Optional.of(product);

// op1 == op2 => false, expected true

if (op1 == op2) { ...

首選:

Product product = new Product();

Optional<Product> op1 = Optional.of(product);

Optional<Product> op2 = Optional.of(product);

// op1.equals(op2) => true,expected true

if (op1.equals(op2)) { ...

第26項(xiàng):如果Optional為空,則返回一個(gè)布爾值。首選Java 11,Optional.isEmpty()

從Java 11開始,true如果方法Optional為,則可以很容易地返回a isEmpty()。

避免使用(Java 11+):

// (Java 11+)

public Optional<String> fetchCartItems(long id) {

  Cart cart = ... ; // this may be null

  ...  

  return Optional.ofNullable(cart);

}

public boolean cartIsEmpty(long id) {

  Optional<String> cart = fetchCartItems(id);

  return !cart.isPresent();

首選(Java 11+):

// (Java 11

public Optional<String> fetchCartItems(long id) {
  Cart cart = ... ; // this may be null

  ...  

  return Optional.ofNullable(cart);

}

public boolean cartIsEmpty(long id) {

  Optional<String> cart = fetchCartItems(id);

  return cart.isEmpty();

}

這就是總結(jié)的這26個(gè)例子,希望可以避免這些陷阱,永遠(yuǎn)不會(huì)出現(xiàn):java.lang.NullPointerException

到此這篇關(guān)于Java Optional解決空指針異常總結(jié)(java 8 功能)的文章就介紹到這了,更多相關(guān)Java Optional空指針異常內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot讀取properties配置文件中的數(shù)據(jù)的三種方法

    SpringBoot讀取properties配置文件中的數(shù)據(jù)的三種方法

    本文主要介紹了SpringBoot讀取properties配置文件中的數(shù)據(jù)的三種方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-06-06
  • mybatis-plus id主鍵生成的坑

    mybatis-plus id主鍵生成的坑

    這篇文章主要介紹了mybatis-plus id主鍵生成的坑,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • 教你在?Java?中實(shí)現(xiàn)?Dijkstra?最短路算法的方法

    教你在?Java?中實(shí)現(xiàn)?Dijkstra?最短路算法的方法

    這篇文章主要教你在?Java?中實(shí)現(xiàn)?Dijkstra?最短路算法的方法,在實(shí)現(xiàn)最短路算法之前需要先實(shí)現(xiàn)帶權(quán)有向圖,文章中給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-04-04
  • JavaWeb項(xiàng)目FullCalendar日歷插件使用的示例代碼

    JavaWeb項(xiàng)目FullCalendar日歷插件使用的示例代碼

    本篇文章主要介紹了JavaWeb項(xiàng)目FullCalendar日歷插件使用的示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-08-08
  • Spring Boot console log 格式自定義方式

    Spring Boot console log 格式自定義方式

    這篇文章主要介紹了Spring Boot console log 格式自定義方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java利用Reflect實(shí)現(xiàn)封裝Excel導(dǎo)出工具類

    Java利用Reflect實(shí)現(xiàn)封裝Excel導(dǎo)出工具類

    這篇文章主要為大家詳細(xì)介紹了Java如何利用Reflect實(shí)現(xiàn)封裝Excel導(dǎo)出工具類,文中的實(shí)現(xiàn)方法講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下
    2022-11-11
  • springboot2.5.6集成RabbitMq實(shí)現(xiàn)Topic主題模式(推薦)

    springboot2.5.6集成RabbitMq實(shí)現(xiàn)Topic主題模式(推薦)

    這篇文章主要介紹了springboot2.5.6集成RabbitMq實(shí)現(xiàn)Topic主題模式(推薦),pom.xml引入依賴和常量類創(chuàng)建,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2021-11-11
  • Spring Boot(二)之web綜合開發(fā)

    Spring Boot(二)之web綜合開發(fā)

    本篇文章為大家介紹spring boot的其它特性(有些未必是spring boot體系桟的功能,但是是spring特別推薦的一些開源技術(shù)本文也會(huì)介紹),對(duì)了這里只是一個(gè)大概的介紹,特別詳細(xì)的使用我們會(huì)在其它的文章中來展開說明
    2017-05-05
  • spring使用OXM進(jìn)行對(duì)象XML映射解析

    spring使用OXM進(jìn)行對(duì)象XML映射解析

    這篇文章主要介紹了spring使用OXM進(jìn)行對(duì)象XML映射解析,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2017-12-12
  • Java字符串split使用方法代碼實(shí)例

    Java字符串split使用方法代碼實(shí)例

    這篇文章主要介紹了Java字符串split使用方法代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07

最新評(píng)論