使用Java Optional類的最佳實踐 - oracle
請遵循以下十二種最佳實踐,以保護您的應用程式免受醜陋的空指標異常的侵擾,並使您的程式碼更具可讀性和簡潔性。
每個認真的Java開發人員或架構師都曾經聽說過或經歷過NullPointerException異常的滋擾。Java工程師一直致力於解決該null問題很長時間,在Java 8中,新增了一個稱為的新型別Optional<T>,Optional原本是一種返回型別,當與流(或return的方法Optional)組合以構建流暢的API時使用。此外,它旨在幫助開發人員null正確處理引用。
下面談談如何避免使用Optional反模式? 或者說不正確用法:
1:切勿將null分配給可選變數。
有時,當開發人員正在處理資料庫以尋找Employee時,他們設計了return的方法Optional<Employee>。我發現null如果資料庫沒有返回任何結果,開發人員仍會返回,例如:
public Optional<Employee> getEmployee(int id) { // perform a search for employee Optional<Employee> employee = null; // in case no employee return employee; } |
上面的程式碼不正確,應該完全避免。要更正它,您應該將第3行替換為以下行,該行Optional以空初始化Optional:
Optional<Employee> employee = Optional.empty(); |
2:不要直接呼叫get()
Optional<Employee> employee = HRService.getEmployee(); Employee myEmployee = employee.get(); |
您是否猜到“Employee”Optional裡面是空著,所以get()直接打電話會丟擲一個“ java.util.NoSuchElementException?”。您應該始終首先使用該isPresent()方法檢查值的存在,如下所示:
if (employee.isPresent()) { Employee myEmployee = employee.get(); ... // do something with "myEmployee" } else { ... // do something that doesn't call employee.get() } |
請注意,上面的程式碼是樣板程式碼,現實中這樣做是不可取的。接下來,您將看到很多優雅的呼叫isPresent()/get()對替代方法。
3. 避免使用isPresent()和get()對來設定和返回值。
public static final String DEFAULT_STATUS = "Unknown"; ... public String getEmployeeStatus(long id) { Optional<String> empStatus = ... ; if (empStatus.isPresent()) { return empStatus.get(); } else { return DEFAULT_STATUS; } } |
只需使用orElse()替換isPresent()和get()配對,如以下:
public String getEmployeeStatus(long id) { Optional<String> empStatus = ... ; return empStatus.orElse(DEFAULT_STATUS); } |
這裡要考慮的一個非常重要的注意事項是可能的效能損失:orElse()無論可選值的存在與否,總是會評估返回的值。因此,這裡的規則是orElse()在您已經預先構造了值並且不使用昂貴的計算值時使用。
4. 請勿使用orElse()返回計算值。
避免使用orElse()返回計算值,因為這會降低效能。考慮以下程式碼片段:
Optional<Employee> getFromCache(int id) { System.out.println("search in cache with Id: " + id); // get value from cache } Optional<Employee> getFromDB(int id) { System.out.println("search in Database with Id: " + id); // get value from database } public Employee findEmployee(int id) { return getFromCache(id) .orElse(getFromDB(id) .orElseThrow(() -> new NotFoundException("Employee not found with id" + id)));} |
首先,程式碼嘗試從快取中獲取具有給定ID的Employee,如果該Employee不在快取中,則嘗試從資料庫中獲取Employee。然後,如果員工不在快取或資料庫中,則程式碼將引發一個NotFoundException。如果執行此程式碼,而僱員在快取中,則會列印以下內容:
Search in cache with Id: 1 Search in Database with Id: 1 |
即使將Employee從快取中返回,資料庫查詢仍然被呼叫。很昂貴,對不對?取而代之的是,我將使用orElseGet(Supplier<? extends T> supplier),就像,orElse()但有一個區別:如果theOptional為空,則orElse()直接返回預設值,而orElseGet()允許您傳遞Supplier僅當theOptional為空時才呼叫的函式。這對效能非常有用。
public Employee findEmployee(int id) { return getFromCache(id) .orElseGet(() -> getFromDB(id) .orElseThrow(() -> { return new NotFoundException("Employee not found with id" + id); })); } |
這次,您將獲得所需的內容並提高了效能:該程式碼將僅列印以下內容:
Search in cache with Id: 1 |
不要考慮使用isPresent()和get()配對,因為它們並不雅緻。
orElseThrow()方法自Java 10起就存在。
5.如果僅當存在Optional值時才想執行操作,請不要使用isPresent()-get()。
Optional<String> confName = Optional.of("CodeOne"); if(confName.isPresent()) System.out.println(confName.get().length()); |
只需將上面的第2行和第3行替換為一行,如下所示:
confName.ifPresent( s -> System.out.println(s.length())); |
ifPresent()方法不返回任何內容,並且自Java 8起就存在。
如果不存在值,則不要使用isPresent()-get()執行基於空的操作。6.
開發人員有時會編寫程式碼,如果存在Optional值,該程式碼會執行某些操作,但如果不存在,則執行基於空的操作,如下所示:
Optional<Employee> employee = ... ; if(employee.isPresent()) { log.debug("Found Employee: {}" , employee.get().getName()); } else { log.error("Employee not found"); } |
請注意,ifPresentOrElse()就像是ifPresent(),唯一的區別是,它涵蓋了else分支為好。因此,您可以將第2行到第6行替換為:
employee.ifPresentOrElse( emp -> log.debug("Found Employee: {}",emp.getName()), () -> log.error("Employee not found")); |
ifPresentOrElse()方法自Java 9起就存在。
7.不存在任何值時,返回另一個Optional。
在某些情況下,如果Optional中有值存在,則返回一個Optional描述值的描述;否則,返回Optional由供應功能產生的產品。避免執行以下操作:
Optional<String> defaultJobStatus = Optional.of("Not started yet."); public Optional<String> fetchJobStatus(int jobId) { Optional<String> foundStatus = ... ; // fetch declared job status by id if (foundStatus.isPresent()) return foundStatus; else return defaultJobStatus; } |
不要過度使用orElse()ororElseGet()方法來完成此操作,因為這兩個方法都返回一個未包裝的值。因此,也請避免執行以下操作:
public Optional<String> fetchJobStatus(int jobId) { Optional<String> foundStatus = ... ; // fetch declared job status by id return foundStatus.orElseGet(() -> Optional.<String>of("Not started yet.")); } |
完美而優雅的解決方案是使用該 (Supplier<? extends Optional<? extends T>> supplier)方法,如下所示:
public Optional<String> fetchJobStatus(int jobId) { Optional<String> foundStatus = ... ; // fetch declared job status by id return foundStatus.or(() -> defaultJobStatus); } |
或者,即使沒有defaultJobStatus在開始時定義可選的內容,也可以使用以下程式碼替換第3行中的程式碼:
return foundStatus.or(() -> Optional.of("Not started yet.")); |
如果提供函式為或產生結果,則or()丟擲NullPointerExceptionnull異常。從Java 9開始就存在此方法。
8.無論是否為空,都獲取Optional的狀態。
從Java 11開始,您可以Optional使用isEmpty()方法直接檢查an是否為空。
public boolean isMovieListEmpty(int id){ Optional<MovieList> movieList = ... ; return !movieList.isPresent(); } |
您可以將第3行替換為以下行,以使程式碼更具可讀性:
return movieList.isEmpty(); |
9.不要過度使用Optional。
有時,開發人員傾向於過度使用他們喜歡的東西,而Optional類就是其中之一。
1 public String fetchJobStatus(int jobId) { 2 String status = ... ; // fetch declared job status by id 3 return Optional.ofNullable(status).orElse("Not started yet."); 4 } |
通過使用以下更清晰的程式碼行替換第3行,可以很簡單:
return status == null ? "Not started yet." : status; |
相關文章
- Java Optional使用的最佳實踐Java
- Java 的最佳實踐Java
- 使用 Java Native Interface 的最佳實踐Java
- Java8 Optional類Java
- Java最佳實踐Java
- Java 8 新特性---Optional類Java
- 講講Java8的Optional類Java
- Java null最佳實踐JavaNull
- Java 反射最佳實踐Java反射
- Java Map的最佳實踐 - tremblayJavaREM
- Java集合框架的最佳實踐Java框架
- Java 8新特性(三):Optional類Java
- java8特性 Optional 工具類Java
- Java Optional使用指南Java
- Java 斷言 Assert 使用教程與最佳實踐Java
- Optional原始碼解析與實踐原始碼
- ?Java8新特性之Optional類Java
- java8 新特性之Optional 類Java
- Java8 新特性之 Optional 類Java
- Java最佳實踐小結 - jonathangilesJava
- Java 日誌管理最佳實踐Java
- 使用GitHub的十個最佳實踐Github
- 使用Java8中的Optional類來消除程式碼中的null檢查JavaNull
- PHP 無限級分類最佳實踐PHP
- 使用 Java 8 Optional 的正確姿勢Java
- Java 8中的Lambda表示式最佳實踐Java
- 10個精妙的Java編碼最佳實踐Java
- Java中的異常處理最佳實踐Java
- Java8 Lambda表示式、Optional類淺析Java
- 【TABLESPACE】Oracle表空間最佳實踐Oracle
- Oracle RAT介紹及最佳實踐Oracle
- Oracle高可用最佳實踐總結Oracle
- 使用Android API最佳實踐AndroidAPI
- 在Java中使用Optional效能很慢 - pkolaczkJava
- 處理Java異常的9個最佳實踐Java
- Java程式設計師的八個最佳實踐Java程式設計師
- Java異常處理的9個最佳實踐Java
- 處理Java異常的10個最佳實踐Java