Java 8ではjava.utilパッケージに新しいクラスOptionalが導入されました。値が存在するかどうかを表すために使用されます。この新しい構造の主な利点は、あまりにも多くのヌルチェックと `NullPointerException`がなくなることです。ランタイム `NullPointerExceptions`を回避し、クリーンできちんとしたJava APIやアプリケーションの開発をサポートします。

コレクションや配列と同様、最大でも1つの値を保持するコンテナです。この新しい構文をいくつかの有用な例を用いて探求しましょう。

Java 8の利点オプション:

  1. ヌルチェックは不要です.

  2. 実行時にNullPointerExceptionが発生することはありません.

  3. きれいできちんとしたAPIを開発することができます.

  4. ボイラープレートのコードはもうありません

1.オプションの基本例

`Optional.ofNullable()`メソッドは、指定されたオブジェクトに値が存在すれば空ではないオプションを返します。それ以外の場合は空を返します。

`Optionaal.empty()`メソッドは、空のOptionalオブジェクトを作成するのに便利です。

OptionalBasicExample.java

package com.techfou;

import java.util.Optional;

public class OptionalBasicExample {

    public static void main(String[]args) {

        Optional<String> 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));

    }

}

出力

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.<init>(Optional.java:96)
    at java.util.Optional.of(Optional.java:108)
   //...

2. Optional.mapとflatMap

OptionalMapFlapMapExample.java

package com.techfou;

import java.util.Optional;

public class OptionalMapFlapMapExample {

    public static void main(String[]args) {

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

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

        Optional<Optional<String>> 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)));

    }

}

出力

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

===  3.オプションのフィルタ

OptionalFilterExample.java

package com.mkyong;

import java.util.Optional;

public class OptionalFilterExample {

public static void main(String[]args) {

Optional<String> gender = Optional.of("MALE");
Optional<String> 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

}

}

出力

Optional.empty
Optional[MALE]Optional.empty

===  4.オプションのisPresentとifPresent

`Optional.isPresent()`は、指定されたOptionalオブジェクトが空でない場合にtrueを返します。それ以外の場合はfalseを返します。

`Optional.ifPresent()`は、指定されたOptionalオブジェクトが空でない場合に、指定されたアクションを実行します。それ以外の場合はfalseを返します。

OptionalIfPresentExample.java

package com.mkyong;

import java.util.Optional;

public class OptionalIfPresentExample {

public static void main(String[]args) {

Optional<String> gender = Optional.of("MALE");
Optional<String> 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."));

}

}

出力

Value available.
In gender Option, value available.

=== オプションのorElseメソッド

オプションのコンテナに値がある場合は値を返します。そうでない場合、与えられたデフォルト値を返します。

OptionalOrElseExample.java

package com.mkyong;

import java.util.Optional;

public class OptionalOrElseExample {

public static void main(String[]args) {

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

System.out.println(gender.orElse("<N/A>"));//MALE
System.out.println(emptyGender.orElse("<N/A>"));//<N/A>

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

}

}

出力

MALE
<N/A>
MALE
<N/A>

===  6. Java 8なしのオプション

誰もがオンラインショッピングに精通しているので。有名な電子商取引のウェブサイト用モバイル製品モジュールを実装したいと考えてみましょう。

Mobile Domain module without Java 8を実装してみましょう。

ScreenResolution.java

package com.mkyong.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.mkyong.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.mkyong.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;
}

}

ここで `getMobileScreenWidth()`メソッドを観察すると、ヌルチェックが多いボイラープレートコードがたくさんあります。 Java 8より前では、Runtime NullPointerExceptionsを避けるために、これらの意味のないものをすべて実行する必要があります。

MobileService.java

package com.mkyong.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;

}

}

これらのドメインオブジェクトをテストする1つのテストアプリケーションを開発します。

MobileTesterWithoutOptional.java

package com.mkyong.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);

}

}

出力

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

===  7. Java 8のオプション

今すぐJava 8を使用して同じドメインモデルを開発する任意のきれいできちんとした方法と構造。

__P.S `ScreenResolution.java`は変更されていません。上記を参照してください.__

DisplayFeatures.java

package com.mkyong.with.optional;

import java.util.Optional;

public class DisplayFeatures {

private String size;//In inches
private Optional<ScreenResolution> resolution;

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

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

}

Mobile.java

package com.mkyong.with.optional;

import java.util.Optional;

public class Mobile {

 private long id;
 private String brand;
 private String name;
 private Optional<DisplayFeatures> 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> 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<DisplayFeatures> getDisplayFeatures() {
    return displayFeatures;
}

}

ここで、ヌルチェックとボイラープレートコードを使用せずに `getMobileScreenWidth()` APIをどのようにクリーンにすることができるかを確認できます。実行時にNullPointerExceptionsについて心配する必要はありません。

MobileService.java

package com.mkyong.with.optional;

import java.util.Optional;

public class MobileService {

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

}

}

1つのテストコンポーネントを開発する

MobileTesterWithOptional.java

package com.mkyong.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);
  }
}

出力

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

===  8. Javaオプションはどこに適合しますか?

リアルタイムのRetail Domainユースケースを上回っている場合は、次の場所でJava Optionalの構文が役立つことがわかります。

8.1メソッドパラメータ

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

8.2メソッドの戻り値の型

public Optional<ScreenResolution> getResolution() {
return resolution;
}

8.3コンストラクタパラメータ

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

8.4変数宣言

private Optional<ScreenResolution> resolution;

8.5クラスレベル

public class B

public class A<T extends Optional<B>> { }

=== ソースコードをダウンロードする

ダウンロード:link://wp-content/uploads/2017/02/Java8Optional.zip[Java8Optional-example.zip](4 KB)

=== 参考文献

.  https://docs/

link://タグ/java8/[java8]リンク://タグ/オプション/[オプション]