Javaオプション - orElse()vs orElseGet()

Javaオプション– orElse()vs orElseGet()

1. 前書き

OptionalのAPIには通常、混乱を引き起こす可能性のある2つのメソッドがあります。orElse() orElseGet()です。

このクイックチュートリアルでは、これら2つの違いを確認し、それぞれをいつ使用するかを検討します。

2. 署名

まず、署名を見て基本から始めましょう。

public T orElse(T other)

public T orElseGet(Supplier other)

明らかに、orElse() はタイプのすべてのパラメータを取りますが、orElseGet() はタイプTのオブジェクトを返すタイプSupplierの機能インターフェイスを受け入れます。

さて、彼らのJavadocsに基づいて:

  • orElse():存在する場合は値を返し、存在しない場合はotherを返します。

  • orElseGet():は、存在する場合は値を返します。存在しない場合は、other を呼び出し、その呼び出しの結果を返します。

3. 違い

この単純化された定義に少し混乱するのは簡単なので、もう少し深く掘り下げて、実際の使用シナリオをいくつか見てみましょう。

3.1. orElse()

loggerが適切に構成されていると仮定して、簡単なコードの記述から始めましょう。

String name = Optional.of("example")
  .orElse(getRandomName());

getRandomName() は、names:List<String>からランダムなname を返すメソッドであることに注意してください。

public String getRandomName() {
    LOG.info("getRandomName() method - start");

    Random random = new Random();
    int index = random.nextInt(5);

    LOG.info("getRandomName() method - end");
    return names.get(index);
}

コードを実行すると、コンソールに次のメッセージが出力されます。

getRandomName() method - start
getRandomName() method - end

変数name は、コード実行の最後に “example” を保持します。

これにより、parameter of orElse() is evaluated even when having a non-empty Optional.が簡単に推測できます。

3.2. orElseGet()

それでは、orElseGet()を使用して同様のコードを書いてみましょう。

String name = Optional.of("example")
  .orElseGet(() -> getRandomName());

上記のコードはgetRandomName() methodを呼び出しません。

(Javadocから)引数として渡されたSupplier メソッドは、an Optional valueが存在しない場合にのみ実行されることに注意してください。

したがって、この場合にorElseGet() を使用すると、ランダムなnameの計算にかかる時間を節約できます。

4. パフォーマンスの影響の測定

ここで、パフォーマンスの違いも理解するために、JMHを使用して、実際の数値をいくつか見てみましょう。

@Benchmark
@BenchmarkMode(Mode.AverageTime)
public String orElseBenchmark() {
    return Optional.of("example").orElse(getRandomName());
}

AndorElseGet()

@Benchmark
@BenchmarkMode(Mode.AverageTime)
public String orElseGetBenchmark() {
    return Optional.of("example").orElseGet(() -> getRandomName());
}

ベンチマークメソッドを実行すると、次の結果が得られます。

Benchmark           Mode  Cnt      Score       Error  Units
orElseBenchmark     avgt   20  60934.425 ± 15115.599  ns/op
orElseGetBenchmark  avgt   20      3.798 ±     0.030  ns/op

ご覧のように、このような単純なユースケースのシナリオでも、パフォーマンスへの影響はかなり大きい可能性があります。

上記の数値はわずかに異なる場合がありますが、orElseGet() has clearly outperformed orElse() for our particular example.

結局のところ、orElse() には、実行ごとのgetRandomName() メソッドの計算が含まれます。

5. 重要なことは何ですか?

パフォーマンスの側面とは別に、他の価値を考慮する要因には以下が含まれます。

  • メソッドが追加のロジックを実行する場合はどうなりますか? E.g. いくつかのDBの挿入または更新を行う

  • オブジェクトをorElse() parameterに割り当てた場合でも:

    String name = Optional.of("example").orElse("Other")

    理由もなく、まだ“Other” objectを作成しています

そのため、ニーズに応じてorElse() orElseGet() の間で慎重に決定することが重要です–by default, it makes more sense to use orElseGet() every time unless the default object is already constructed and accessible directly.

6. 結論

この記事では、Optional orElse() メソッドとOrElseGet() メソッドの間の微妙な違いを学びました。 また、このような単純な概念がより深い意味を持つことがあることに気付きました。

いつものように、完全なソースコードはover on Githubにあります。