日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 8可选

發布時間:2023/12/3 java 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 8可选 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在編程時,我們都面臨著最( 臭名昭著 )的NullPointerException 。 而且我相信我們所有人都同意,遇到NullPointerException也是一種痛苦。 為了使讀者了解最新情況,著名的計算機科學家Tony Hoare引入了引用,他認為這是一百萬美元的錯誤 。 眾所周知,這很容易實現,但是也很難預測。 這就是為什么開發人員需要非常謹慎的原因。

通常的方式

讓我們考慮以下3個簡單的POJO。

public class Employee {private Car car;public Car getCar() {return car;} }public class Car {private Insurance insurance;public Insurance getInsurance() {return insurance;} }public class Insurance {private String name;public String getName() {return name;} }

僅提供背景信息-員工可以擁有汽車(雖然不是強制性的),汽車可以具有保險(不一定),并且保險必須始終具有名稱。 只要記住了解以下內容即可。

現在,我們想通過提供人員實例來獲得保險的名稱。

public String getInsuranceName(Employee employee) {if (employee != null) {Car car = employee.getCar();if (car != null) {Insurance insurance = car.getInsurance();if (insurance != null) {return insurance.getName();}}}return "UNKNOWN"; }

這是我們通常采取的預防措施,這樣就不會遇到可怕的NullPointerException 。 我們還認為這也會污染源代碼,根據我的觀點,應將其視為反模式。

另一種慣用的方式

上一節中提到的對null檢查的這種深層嵌套看起來有些晦澀。 有時人們會以不同的方式來做。

public String getInsuranceName(Employee employee) {if (employee == null) {return "UNKNOWN";}Car car = employee.getCar();if (car == null) {return "UNKNOWN";}Insurance insurance = car.getInsurance();if (insurance == null) {return "UNKNOWN";}return insurance.getName(); }

在我看來,這還算不錯,因為它不包含深層嵌套的null檢查。 但是它仍然遵循相同的反模式,以不同的方式檢查空值。

為什么NULL不好?

  • 這會降低源代碼的可讀性
  • 呈現沒有價值的東西在語義上是不正確的
  • 它與Java的思想背道而馳,因為Java會向開發人員隱藏指針(除非存在空引用的情況)
  • NULL的替代

    很少有語言(例如Scala,Groovy)消除了對空引用(表示沒有值)的可怕使用。 可以以非常簡潔的方式用Groovy編寫類似的代碼。

    def name = employee?.car?.insurance?.name

    這在Groovy中被稱為“ 安全導航”操作符 ,它清楚地顯示了易讀的代碼,同時消除了遇到可怕的空引用的可能性。

    Java的努力

    現在我們應該問,Java開發人員可以做什么來實現類似的事情,從而在保持可讀性和可維護性的源代碼的同時,防止NullPointerException的可能性。 Java語言設計人員選擇了Groovy或Scala語言已經實現的類似方法,但是引入了一個新類-Optional

    可選的

    public final class Optional<T> {public static<T> Optional<T> empty() {}public static <T> Optional<T> of(T value) {}public static <T> Optional<T> ofNullable(T value) {}public T get() {}public boolean isPresent() {}public void ifPresent(Consumer<? super T> consumer) {}public Optional<T> filter(Predicate<? super T> predicate) {}public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {}public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {}public T orElse(T other) {}public T orElseGet(Supplier<? extends T> other) {}public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {} }

    此類主要用于表示值的不存在。 如果您認為一個值可以始終存在或不能始終存在,則最好使用Optional類型。 在我們前面的示例中,員工可能會或可能不會載有汽車,這就是為什么最好返回Optional <Car>而不是簡單地返回Car

    讓我們看看我們如何設計上一個示例:

    public class Employee {private Car car;public Optional<Car> getCar() {return Optional.ofNullable(car);} }public class Car {private Insurance insurance;public Optional<Insurance> getInsurance() {return Optional.ofNullable(insurance);} }public class Insurance {private String name;public String getName() {return name;} }

    我沒有討論過靜態工廠ofNullable(..)方法,而只是將其視為包裝值的包裝實用程序方法,而不管其引用如何。

    只需查看API,就可以輕松了解遇到可選類型時需要執行的操作。 對于開發人員而言,遇到此類可選類型總是表示缺少值的可能性,因此開發人員可以為此采取適當的措施。

    可選創作

    從類概述中,我們可以清楚地看到可以以多種方式創建Optional

  • of(..) :這允許創建包裝非空值的Optional實例
  • empty() :這將創建一個空的Optional
  • ofNullable(..) :這允許創建一個包裝任何值(空或非空)的Optional實例
  • 可選的提取和轉換

    到目前為止,我們已經看到了如何創建Optional實例。 現在我們應該看看如何提取值或將其轉換為另一個值。

  • get()返回包含的值,如果Optional實例為空,則拋出NoSuchElementException
  • 但是我們應該如何使用呢?

    Car car = employee.getCar(); if (employee != null) {car = employee.getCar(); }

    這是我們逃避NullPointerException的主要工作。 現在,使用Java 8 Optional ,我們可以編寫如下代碼:

    Optional<Car> car = employee.getCar(); if (!car.isEmpty()) {Car car = car.get(); }

    但是,您是否認為這是對討厭的null檢查的改進?

    我曾經認為它是一種改進,因為它隱藏了空指針,但后來,我覺得它會污染源代碼。 但是我不反對使用從方法或包裝變量中返回Optional作為類型的方法。 我將在以下各節中討論其背后的原因。

    讓我們考慮以前的方法:

    public String getInsuranceName(Employee employee) {return employee.getCar().getInsurance().getName(); }

    這是一個非常干凈的代碼,但是NullPointerException卻藏在后面,這就是為什么我們需要合并幾個空引用檢查(我們之前已經看到過)的原因。

    如果我們在設計一個好的API時合并了公共String Optional ,則可以通過更簡潔的方式實現:

    public String getInsuranceName(Optional<Employee> employee) {return employee.flatMap(Employee::getCar).flatMap(Car::getInsurance).map(Insurance::getName).orElse("UNKNOWN"); }

    這是不是真的好又干凈的方法? 我知道這會使一些對Java Streams API不滿意的程序員感到困惑。 我強烈建議對Java 8 Streams有一個快速的了解,以了解Optional的優點。

    另一個示例是如果人名以“ P”開頭,則獲得保險名稱

    public String getInsuranceName(Optional<Employee> employee) {return employee.filter(e-> e.getName().startsWith("P")).flatMap(Employee::getCar).flatMap(Car::getInsurance).map(Insurance::getName).orElse("UNKNOWN"); }

    設計實踐

    現在,我想以一些不同的方式分享一些有關設計我們先前討論的POJO的想法。

    API設計實踐1

    public class Employee {private Optional<Car> car;public Optional<Car> getCar() {return car;} }public class Car {private Optional<Insurance> insurance;public Insurance getInsurance() {return insurance;} }public class Insurance {private String name;public String getName() {return name;} }

    在這里,我已聲明成員變量為Optional類型。 根據我的觀點,這也是非常用戶友好的,并且此類的用戶或消費者可以輕松理解此類的性質。 在這種情況下,員工汽車是Optional的 ,也就是說,員工可能可能沒有汽車。

    API設計實踐2

    public class Employee {private Car car;public Optional<Car> getCar() {return Optional.ofNullable(car);} }public class Car {private Insurance insurance;public Optional<Insurance> getInsurance() {return Optional.ofNullable(insurance);} }public class Insurance {private String name;public String getName() {return name;} }

    這也是非常直觀的,但是缺乏清晰顯示成員實例不存在的想法。 要了解任何系統,開發人員總是需要首先了解對象模型,而了解對象模型則需要我們了解領域對象。 在這種情況下,員工是擁有汽車的域對象,就像它對員工是強制性的一樣。 但實際上,員工可能會或可能不會有汽車。 我們可以在獲取或檢索其值( getCar() )時實現它,然后當該方法返回Optional時 ,我們可能會注意到它缺少包含值的可能性。

    使用什么?

    它完全取決于開發人員。 我個人更喜歡第一種方法,因為很明顯在理解領域模型方面很明顯,而第二種方法在序列化方面具有優勢。 由于Optional不實現Serializable ,因此在我們的第一種方法中它不可序列化。 如果我們使用DTO,則可以使我們的實現適應第二種方法。

    方法或構造函數參數中的可選

    正如我之前提到的,“ 可選”在班級中清楚地表明了消費者應該做的事情。 因此,如果構造函數或方法接受Optional元素作為參數,則意味著該參數不是必需的。

    另一方面,我們需要付出使用Optional污染代碼庫的代價。 開發人員唯一要謹慎使用它。 我個人不希望在方法參數中使用Optional ,但如果需要,我們仍然可以將其包裝在Optional實例中并對其執行必要的操作。

    方法返回類型中的可選

    Java語言架構師Brian Goetz還建議,如果有可能返回null,則在方法中返回Optional 。 我們已經在API設計規范2中看到了這一點。

    從方法拋出異常或返回可選

    多年來,Java開發人員遵循通常的方法引發異常來表示方法調用中的錯誤情況。

    public static InputStream getInputStream(final String path) {checkNotNull(path, "Path cannot be null");final URL url = fileSystem.getEntry(path);InputStream xmlStream;try {xmlStream = url.openStream();return xmlStream;} catch (final IOException ex) {throw new RuntimeException(ex);} }

    如果此方法的使用者遇到RuntimeException ,那是由于打開與指定URL的連接時出現的問題。 另一方面,我們還可以通過以下方式使用Optional

    public static Optional<InputStream> getInputStream(final String path) {checkNotNull(path, "Path cannot be null");final URL url = fileSystem.getEntry(path);InputStream xmlStream;try {xmlStream = url.openStream();return Optional.of(xmlStream);} catch (final IOException ex) {return Optional.empty();} }

    我認為這很直觀,因為它清楚地表明它返回一個可能具有或沒有值的Optional實例。 這就是為什么我傾向于從可能具有這種空遇到可能性的方法中返回Optional的原因。

    私有方法中的可選返回類型

    私有方法顯然不是要理解或分析項目的任何重要部分。 因此,我認為我們仍然可以使用null檢查來擺脫過多的Optional,但是如果您認為仍然可以以更簡潔明了的方式使用該方法,則也可以返回Optional

    為了更好地理解,我編寫了一個示例,如下所示:

    private void process(final String data) {try {final ItemList nList = doc.getChildNodes();for (int temp = 0; temp < nList.getLength(); temp++) {final Node nNode = nList.item(temp);final String key = nNode.getName();final String value = nNode.getValue();values.put(getAttribute(key).orElseThrow(IllegalArgumentException::new), value);}} catch (final Exception ex) {logger.error("{}", ex.getMessage(), ex);} }private Optional<Attribute> getAttribute(final String key) {return Arrays.stream(Attribute.values()).filter(x -> x.value().filter(y -> y.equalsIgnoreCase(key)).isPresent()).findFirst(); }public static enum Attribute {A ("Sample1"),B ("Sample2"),C ("Sample3");private String value;private Attribute(String value) {this.value = value;}public Optional<String> value() {return Optional.ofNullable(value);}}

    我本可以以更常用的方式編寫第二種方法:

    private Attribute getAttribute(final String key) {for (final Attribute attribute : Attribute.values()) {Optional<String> value = attribute.value();if (value.isPresent() && value.get().equalsIgnoreCase(key)) {return attribute;}}throw new IllegalArgumentException(); }

    私有方法中返回返回Collection或其任何子類型的可選返回類型

    作為第一個示例,請考慮您需要實現一種從Java中指定路徑列出文件的方法的代碼。

    public static List<String> listFiles(String file) {List<String> files;try {files = Files.list(Paths.get(path));} catch (IOException e) {files = Arrays.asList("Could not list");}return files; }

    我們可以實現更簡潔的代碼,如下所示:

    public static List<String> listFiles(String path) {return Files.list(Paths.get(path)).filter(Files::isRegularFile).collect(toList()); }

    注意,簡潔方法中的返回類型仍為List而不是Optional 。 最好遵循返回空列表的通常做法,而不是使用Optional

    使用Optional的流方式更加簡潔是非常有專利的。 可選的是實用程序數據容器,可幫助開發人員擺脫空引用。 另外,它確實提供了許多有用的方法來簡化程序員的任務。 但是,如果開發人員不太了解Optional的主要用法,則Optional可能會被嚴重濫用,并可能污染代碼庫。 這就是為什么我強烈建議大家在Optional中使用面向流的方法,以幫助開發人員編寫簡潔且可維護的代碼

    翻譯自: https://www.javacodegeeks.com/2017/07/java-8-optionals.html

    創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的Java 8可选的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。