Java 8 Optional Tiefe

Java 8 Optional im Detail

Java 8 hat eine neue Klasse Optional im Paket java.util eingeführt. Es wird verwendet, um darzustellen, dass ein Wert vorhanden oder nicht vorhanden ist. Der Hauptvorteil dieses neuen Konstrukts besteht darin, dass nicht mehr zu viele Nullprüfungen undNullPointerException durchgeführt werden. Es vermeidet jede LaufzeitNullPointerExceptions und unterstützt uns bei der Entwicklung sauberer und ordentlicher Java-APIs oder -Anwendungen. Wie Sammlungen und Arrays ist es auch ein Container, der höchstens einen Wert enthält. Lassen Sie uns dieses neue Konstrukt anhand einiger nützlicher Beispiele untersuchen.

Vorteile von Java 8 Optional:

  1. Nullprüfungen sind nicht erforderlich.

  2. Keine NullPointerException mehr zur Laufzeit.

  3. Wir können saubere und ordentliche APIs entwickeln.

  4. Kein Kesselschildcode mehr

1. Optionales Basisbeispiel

Die MethodeOptional.ofNullable()gibt eine nicht leere Option zurück, wenn ein Wert im angegebenen Objekt vorhanden ist. Andernfalls wird leer zurückgegeben. Optional.

Die Methode vonOptionaal.empty()ist nützlich, um ein leeres optionales Objekt zu erstellen.

OptionalBasicExample.java

package com.example;

import java.util.Optional;

public class OptionalBasicExample {

    public static void main(String[] args) {

        Optional gender = Optional.of("MALE");
        String answer1 = "Yes";
        String answer2 = null;

        System.out.println("Non-Empty Optional:" + gender);
        System.out.println("Non-Empty Optional: Gender value : " + gender.get());
        System.out.println("Empty Optional: " + Optional.empty());

        System.out.println("ofNullable on Non-Empty Optional: " + Optional.ofNullable(answer1));
        System.out.println("ofNullable on Empty Optional: " + Optional.ofNullable(answer2));

        // java.lang.NullPointerException
        System.out.println("ofNullable on Non-Empty Optional: " + Optional.of(answer2));

    }

}

Ausgabe

Non-Empty Optional:Optional[MALE]
Non-Empty Optional: Gender value : MALE
Empty Optional: Optional.empty

ofNullable on Non-Empty Optional: Optional[Yes]
ofNullable on Empty Optional: Optional.empty

Exception in thread "main" java.lang.NullPointerException
    at java.util.Objects.requireNonNull(Objects.java:203)
    at java.util.Optional.(Optional.java:96)
    at java.util.Optional.of(Optional.java:108)
    //...

2. Optional.map and flatMap

OptionalMapFlapMapExample.java

package com.example;

import java.util.Optional;

public class OptionalMapFlapMapExample {

    public static void main(String[] args) {

        Optional nonEmptyGender = Optional.of("male");
        Optional emptyGender = Optional.empty();

        System.out.println("Non-Empty Optional:: " + nonEmptyGender.map(String::toUpperCase));
        System.out.println("Empty Optional    :: " + emptyGender.map(String::toUpperCase));

        Optional> nonEmptyOtionalGender = Optional.of(Optional.of("male"));
        System.out.println("Optional value   :: " + nonEmptyOtionalGender);
        System.out.println("Optional.map     :: " + nonEmptyOtionalGender.map(gender -> gender.map(String::toUpperCase)));
        System.out.println("Optional.flatMap :: " + nonEmptyOtionalGender.flatMap(gender -> gender.map(String::toUpperCase)));

    }

}

Ausgabe

Non-Empty Optional:: Optional[MALE]
Empty Optional    :: Optional.empty
Optional value   :: Optional[Optional[male]]
Optional.map     :: Optional[Optional[MALE]]
Optional.flatMap :: Optional[MALE]

3. Optional.filter

OptionalFilterExample.java

package com.example;

import java.util.Optional;

public class OptionalFilterExample {

    public static void main(String[] args) {

        Optional gender = Optional.of("MALE");
        Optional emptyGender = Optional.empty();

        //Filter on Optional
        System.out.println(gender.filter(g -> g.equals("male"))); //Optional.empty
        System.out.println(gender.filter(g -> g.equalsIgnoreCase("MALE"))); //Optional[MALE]
        System.out.println(emptyGender.filter(g -> g.equalsIgnoreCase("MALE"))); //Optional.empty

    }

}

Ausgabe

Optional.empty
Optional[MALE]
Optional.empty

4. Optional isPresent und ifPresent

Optional.isPresent() gibt true zurück, wenn das angegebene optionale Objekt nicht leer ist. Andernfalls wird false zurückgegeben.

Optional.ifPresent() führt eine bestimmte Aktion aus, wenn das angegebene optionale Objekt nicht leer ist. Andernfalls wird false zurückgegeben.

OptionalIfPresentExample.java

package com.example;

import java.util.Optional;

public class OptionalIfPresentExample {

    public static void main(String[] args) {

        Optional gender = Optional.of("MALE");
        Optional emptyGender = Optional.empty();

        if (gender.isPresent()) {
            System.out.println("Value available.");
        } else {
            System.out.println("Value not available.");
        }

        gender.ifPresent(g -> System.out.println("In gender Option, value available."));

        //condition failed, no output print
        emptyGender.ifPresent(g -> System.out.println("In emptyGender Option, value available."));

    }

}

Ausgabe

Value available.
In gender Option, value available.

5. Optionale oderElse-Methoden

Es gibt den Wert zurück, falls dieser im optionalen Container vorhanden ist. Andernfalls wird der angegebene Standardwert zurückgegeben.

OptionalOrElseExample.java

package com.example;

import java.util.Optional;

public class OptionalOrElseExample {

    public static void main(String[] args) {

        Optional gender = Optional.of("MALE");
        Optional emptyGender = Optional.empty();

        System.out.println(gender.orElse("")); //MALE
        System.out.println(emptyGender.orElse("")); //

        System.out.println(gender.orElseGet(() -> "")); //MALE
        System.out.println(emptyGender.orElseGet(() -> "")); //

    }

}

Ausgabe

MALE

MALE

6. Ohne Java 8 Optional

Wie jeder mit Online-Shopping vertraut ist. Nehmen wir an, wir möchten ein mobiles Produktmodul für eine bekannte E-Commerce-Website implementieren.

Lassen Sie uns das Mobile Domain-Modul ohne Java 8 Optional implementieren.

ScreenResolution.java

package com.example.without.optional;

public class ScreenResolution {

    private int width;
    private int height;

    public ScreenResolution(int width, int height){
        this.width = width;
        this.height = height;
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }

}

DisplayFeatures.java

package com.example.without.optional;

public class DisplayFeatures {

    private String size; // In inches
    private ScreenResolution resolution;

    public DisplayFeatures(String size, ScreenResolution resolution){
        this.size = size;
        this.resolution = resolution;
    }

    public String getSize() {
        return size;
    }
    public ScreenResolution getResolution() {
        return resolution;
    }

}

Mobile.java

package com.example.without.optional;

public class Mobile {

    private long id;
    private String brand;
    private String name;
    private DisplayFeatures displayFeatures;
    // Likewise we can see Memory Features, Camera Features etc.

    public Mobile(long id, String brand, String name,
                            DisplayFeatures displayFeatures){
        this.id = id;
        this.brand = brand;
        this.name = name;
        this.displayFeatures = displayFeatures;
    }

    public long getId() {
        return id;
    }

    public String getBrand() {
        return brand;
    }

    public String getName() {
        return name;
    }

    public DisplayFeatures getDisplayFeatures() {
        return displayFeatures;
    }

}

Wenn wir hier diegetMobileScreenWidth()-Methode beobachten, hat sie viel Kesselplattencode mit vielen Nullprüfungen. Vor Java 8 sollten wir all diese unsinnigen Dinge tun, um Runtime NullPointerExceptions zu vermeiden.

MobileService.java

package com.example.without.optional;

public class MobileService {

    public int getMobileScreenWidth(Mobile mobile){

        if(mobile != null){
            DisplayFeatures dfeatures = mobile.getDisplayFeatures();
            if(dfeatures != null){
                ScreenResolution resolution = dfeatures.getResolution();
                if(resolution != null){
                    return resolution.getWidth();
                }
            }
        }
        return 0;

    }

}

Entwickeln Sie eine Testanwendung, um diese Domänenobjekte zu testen.

MobileTesterWithoutOptional.java

package com.example.without.optional;

public class MobileTesterWithoutOptional {

    public static void main(String[] args) {

        ScreenResolution resolution = new ScreenResolution(750,1334);
        DisplayFeatures dfeatures = new DisplayFeatures("4.7", resolution);
        Mobile mobile = new Mobile(2015001, "Apple", "iPhone 6s", dfeatures);

        MobileService mService = new MobileService();

        int mobileWidth = mService.getMobileScreenWidth(mobile);
        System.out.println("Apple iPhone 6s Screen Width = " + mobileWidth);

        ScreenResolution resolution2 = new ScreenResolution(0,0);
        DisplayFeatures dfeatures2 = new DisplayFeatures("0", resolution2);
        Mobile mobile2 = new Mobile(2015001, "Apple", "iPhone 6s", dfeatures2);
        int mobileWidth2 = mService.getMobileScreenWidth(mobile2);
        System.out.println("Apple iPhone 16s Screen Width = " + mobileWidth2);

    }

}

Ausgabe

Apple iPhone 6s Screen Width = 750
Apple iPhone 16s Screen Width = 0

7. Mit Java 8 Optional

Entwickeln Sie jetzt dieselben Domänenmodelle mithilfe des optionalen Java 8-Konstrukts.

P.S ScreenResolution.java no change. Bitte beachten Sie den obigen Abschnitt.

DisplayFeatures.java

package com.example.with.optional;

import java.util.Optional;

public class DisplayFeatures {

    private String size; // In inches
    private Optional resolution;

    public DisplayFeatures(String size, Optional resolution){
        this.size = size;
        this.resolution = resolution;
    }

    public String getSize() {
        return size;
    }
    public Optional getResolution() {
        return resolution;
    }

}

Mobile.java

package com.example.with.optional;

import java.util.Optional;

public class Mobile {

    private long id;
    private String brand;
    private String name;
    private Optional displayFeatures;
    // Like wise we can see MemoryFeatures, CameraFeatures etc.
    // For simplicity, using only one Features

    public Mobile(long id, String brand, String name, Optional displayFeatures){
        this.id = id;
        this.brand = brand;
        this.name = name;
        this.displayFeatures = displayFeatures;
    }

    public long getId() {
        return id;
    }

    public String getBrand() {
        return brand;
    }

    public String getName() {
        return name;
    }

    public Optional getDisplayFeatures() {
        return displayFeatures;
    }

}

Hier können wir beobachten, wie sauber unseregetMobileScreenWidth() API ohne Nullprüfungen und Kesselplattencode ist. Wir kümmern uns nicht um NullPointerExceptions zur Laufzeit.

MobileService.java

package com.example.with.optional;

import java.util.Optional;

public class MobileService {

  public Integer getMobileScreenWidth(Optional mobile){
    return mobile.flatMap(Mobile::getDisplayFeatures)
         .flatMap(DisplayFeatures::getResolution)
         .map(ScreenResolution::getWidth)
         .orElse(0);

  }

}

Entwickeln Sie nun eine Testkomponente

MobileTesterWithOptional.java

package com.example.with.optional;

import java.util.Optional;

public class MobileTesterWithOptional {

  public static void main(String[] args) {
    ScreenResolution resolution = new ScreenResolution(750,1334);
    DisplayFeatures dfeatures = new DisplayFeatures("4.7", Optional.of(resolution));
    Mobile mobile = new Mobile(2015001, "Apple", "iPhone 6s", Optional.of(dfeatures));

    MobileService mService = new MobileService();

    int width = mService.getMobileScreenWidth(Optional.of(mobile));
    System.out.println("Apple iPhone 6s Screen Width = " + width);

    Mobile mobile2 = new Mobile(2015001, "Apple", "iPhone 6s", Optional.empty());
    int width2 = mService.getMobileScreenWidth(Optional.of(mobile2));
    System.out.println("Apple iPhone 16s Screen Width = " + width2);
  }
}

Ausgabe

Apple iPhone 6s Screen Width = 750
Apple iPhone 16s Screen Width = 0

8. Wo passt Java Optional hin?

Wenn wir den obigen Anwendungsfall für Echtzeit-Retail-Domains beobachten, sollten wir wissen, dass das optionale Java-Konstrukt an den folgenden Stellen nützlich ist.

8.1 Method Parameter

public void setResolution(Optional resolution) {
    this.resolution = resolution;
}

8.2 Method Return Type

public Optional getResolution() {
    return resolution;
}

8.3 Constructor Parameter

public DisplayFeatures(String size, Optional resolution){
    this.size = size;
    this.resolution = resolution;
}

8.4 Variable Declaration

private Optional resolution;

8.5 Class Level

public class B

public class A> { }

Quellcode herunterladen

Herunterladen -Java8Optional-example.zip (4 KB)