web-dev-qa-db-ja.com

Optional.orElse()でOptional.orElseGet()を使用する必要がある場合

これを読みましたが、これについては明確な説明が必要です link 違いについてですが、明確ではありません。だから誰もがこれについて簡単にコードで説明してくれます。

11
TVK

私はあなたの質問を理解し始めていると思います。 Optionalを使用した実行順序は、手続き型プログラミングで使用される順序とは異なる場合があります(Javaストリームおよびラムダを使用する他のコードについても同じです)。

Eugene's answer の2つの例を使用します。

_    o1.orElse(new MyObject()); // 1055e4af 
_

これは単純な古いJavaです。orElse()を呼び出して、new MyObject()を引数として取ります。したがって、引数が最初に評価され、新しいMyObjectが作成されます。これはorElse()に渡されます。 orElse()は、Optionalに値が存在するかどうかを確認します。その場合、その値を返します(新しく作成されたオブジェクトを破棄します)。そうでない場合は、引数で指定されたオブジェクトを返します。これは簡単な例です。

_    o1.orElseGet(() -> {
        System.out.println("Should I see this");
        return new MyObject();
    });
_

ここでも、1つの引数を持つメソッド呼び出しがあり、引数が最初に評価されます。ラムダは、サプライヤとしてのみ作成および渡されます。 _{ }_内のコードはまだ実行されていません(Eugeneの出力には_Should I see this_も表示されていません)。再びorElseGetは、Optionalに値が存在するかどうかを確認します。存在する場合、値が返され、渡されたサプライヤーは無視されます。存在しない場合、サプライヤが呼び出され、orElseGet()から返される値を取得するために_{ }_内のコードが実行されます。

最初のケースでは、MyObjectが作成されて無駄になったと言うかもしれません。 2番目では、Supplierが作成され、無駄になります。返されるのは、どちらの場合も簡潔でヌルポインターの安全なコードです。そのため、どれを選ぶかは重要ではありません。 MyObjectの作成に費用がかかるか、望ましくない副作用がある場合、もちろん、オブジェクトが要求されたときにのみ作成され、無駄にならない2番目のバージョンが必要になります。 Eugeneはコメントで、返されたオブジェクトがデータベース呼び出しから来た場合について言及しています。通常、データベースの呼び出しには時間がかかるので、目的のない呼び出しはしたくありません。

34
Ole V.V.

例はどうですか:

static class MyObject {
    public MyObject() {
        System.out.println("Creating one..." + this);
    }
}

そしていくつかの使用法:

  Optional<MyObject> o1 = Optional.of(new MyObject()); // 7382f612

    o1.orElse(new MyObject()); // 1055e4af 
    o1.orElseGet(() -> {
        System.out.println("Should I see this");
        return new MyObject();
    });

そしていくつかの出力:

 Creating one... MyObject@7382f612
 Creating one... MyObject@1055e4af

Optionalの場合値がある; orElseは引き続き呼び出されますが、使用されません。矛盾するorElseGetは呼び出されません。

オブジェクトの作成に費用がかかる場合を考慮してください。どちらを使用しますか?

あなたがコードを見ると、実際には理解しやすいと思います:

public T orElseGet(Supplier<? extends T> supplier) {
    return value != null ? value : supplier.get();
}
13
Eugene

here と答えたように、必要なリソースがgetにかかる場合、2番目のアプローチを検討する必要があります。

// Always get heavy resource
getResource(resourceId).orElse(getHeavyResource()); 

// Get heavy resource when required.
getResource(resourceId).orElseGet(() -> getHeavyResource()) 
1
nxhoaf