1. 序章

別のインスタンスが空の場合は、別のオプションインスタンスにフォールバックしたい場合があります。

このチュートリアルでは、それをどのように行うことができるかについて簡単に説明します。これは見た目よりも難しいことです。

Javaオプションクラスの概要については、以前の記事をご覧ください。

2. Java 8

Java 8では、最初のオプションが空の場合に、別のオプションを返す直接的な方法はありません。

したがって、独自のカスタムメソッドを実装できます。

public static <T> Optional<T> or(Optional<T> optional, Optional<T> fallback) {
    return optional.isPresent() ? optional : fallback;
}

そして、実際には:

@Test
public void givenOptional_whenValue_thenOptionalGeneralMethod() {
    String name = "Filan Fisteku";
    String missingOptional = "Name not provided";
    Optional<String> optionalString = Optional.ofNullable(name);
    Optional<String> fallbackOptionalString = Optional.ofNullable(missingOptional);
 
    assertEquals(
      optionalString, 
      Optionals.or(optionalString, fallbackOptionalString));
}
    
@Test
public void givenEmptyOptional_whenValue_thenOptionalGeneralMethod() {
    Optional<String> optionalString = Optional.empty();
    Optional<String> fallbackOptionalString = Optional.ofNullable("Name not provided");
 
    assertEquals(
      fallbackOptionalString, 
      Optionals.or(optionalString, fallbackOptionalString));
}

2.1. 遅延評価

上記のソリューションには、重大な欠点が1つあります。カスタムor()メソッドを使用する前に、両方のオプション変数を評価する必要があります。

想像してみてください。Optionalを返す2つのメソッドがあり、どちらも内部でデータベースにクエリを実行します。 パフォーマンスの観点から、最初のメソッドが必要な値をすでに返している場合、両方を呼び出すことは受け入れられません。

単純なItemsProviderクラスを作成しましょう。

public class ItemsProvider {
    public Optional<String> getNail(){
        System.out.println("Returning a nail");
        return Optional.of("nail");
    }

    public Optional<String> getHammer(){
        System.out.println("Returning a hammer");
        return Optional.of("hammer");
    }
}

これらのメソッドをチェーンし、遅延評価を利用する方法は次のとおりです。

@Test
public void givenTwoOptionalMethods_whenFirstNonEmpty_thenSecondNotEvaluated() {
    ItemsProvider itemsProvider = new ItemsProvider();

    Optional<String> item = itemsProvider.getNail()
            .map(Optional::of)
            .orElseGet(itemsProvider::getHammer);

    assertEquals(Optional.of("nail"), item);
}

上記のテストケースは、「釘を返す」のみを印刷します。 これは、 getNail()メソッドのみが実行されたことを明確に示しています。

3. Java 9

Java 9にor()メソッドが追加されました。このメソッドを使用して、Optional、またはそのOptionalが存在しない場合に別の値を取得できます

簡単な例でこれを実際に見てみましょう:

public static Optional<String> getName(Optional<String> name) {
    return name.or(() -> getCustomMessage());
}

この例では、補助的な方法を使用して支援しました。

private static Optional<String> getCustomMessage() {
    return Optional.of("Name not provided");
}

それをテストして、それがどのように機能しているかをさらに理解することができます。 次のテストケースは、オプションのに値がある場合のデモンストレーションです。

@Test
public void givenOptional_whenValue_thenOptional() {
    String name = "Filan Fisteku";
    Optional<String> optionalString = Optional.ofNullable(name);
    assertEquals(optionalString, Optionals.getName(optionalString));
}

4. グアバの使用

これを行う別の方法は、グアバのオプションのクラスの or()メソッドを使用することです。 まず、プロジェクトに guava を追加する必要があります(最新バージョンはここにあります):

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>

これで、以前と同じ例を続けることができます。

public static com.google.common.base.Optional<String> 
  getOptionalGuavaName(com.google.common.base.Optional<String> name) {
    return name.or(getCustomMessageGuava());
}
private static com.google.common.base.Optional<String> getCustomMessageGuava() {
    return com.google.common.base.Optional.of("Name not provided");
}

ご覧のとおり、上に表示されているものと非常によく似ています。 ただし、メソッドの命名にわずかな違いがあり、JDK 9のクラスオプションのまたは()メソッドとまったく同じです。

上記の例と同様に、これでテストできます。

@Test
public void givenGuavaOptional_whenInvoke_thenOptional() {
    String name = "Filan Fisteku";
    Optional<String> stringOptional = Optional.of(name);
 
    assertEquals(name, Optionals.getOptionalGuavaName(stringOptional));
}
@Test
public void givenGuavaOptional_whenNull_thenDefaultText() {
    assertEquals(
      com.google.common.base.Optional.of("Name not provided"), 
      Optionals.getOptionalGuavaName(com.google.common.base.Optional.fromNullable(null)));
}

5. 結論

これは、オプションまたはその他のオプション機能を実現する方法を説明する簡単な記事でした。

ここで説明されているすべての例のコード、およびその他の多くのコードは、GitHubにあります。