1. ホーム
  2. java

[解決済み] なぜJava 8のOptionalは引数で使ってはいけないのか

2022-03-19 18:38:14

質問

多くのWebサイトで、Optionalは戻り値の型としてのみ使用し、メソッドの引数には使用すべきではないと書かれています。 論理的な理由がわからず困っています。 例えば、2つのオプションのパラメータを持つロジックがあります。 したがって、私はこのようにメソッドのシグネチャを書くのが理にかなっていると思います(解決策1)。

public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2 {
    // my logic
}

多くの Web ページでは、Optional をメソッドの引数として使用しないよう指定しています。このことを念頭に置いて、私は以下のメソッドシグネチャを使い、Javadocのコメントを追加して、引数がNULLである可能性があることを明記することができます。

public int calculateSomething(String p1, BigDecimal p2) {
    // my logic
}

あるいは、私のメソッドを4つのパブリックメソッドに置き換えて、より良いインターフェイスを提供し、p1とp2がオプションであることをより明確にすることもできます(解決策3)。

public int calculateSomething() {
    calculateSomething(null, null);
}

public int calculateSomething(String p1) {
    calculateSomething(p1, null);
}

public int calculateSomething(BigDecimal p2) {
    calculateSomething(null, p2);
}

public int calculateSomething(String p1, BigDecimal p2) {
    // my logic
}

次に、このロジックを呼び出すクラスのコードを、各アプローチごとに書いてみます。 まず、2つの入力パラメータを別のオブジェクトから取得し、そのオブジェクトは Optional を起動し calculateSomething . したがって、解決策1を使用する場合、呼び出しコードは次のようになります。

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1, p2);

解決策2を使用する場合、呼び出しコードは次のようになります。

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1.orElse(null), p2.orElse(null));

解決策3を適用する場合、上のコードを使うこともできるし、次のコードを使うこともできる(ただし、かなりコード量が増える)。

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result;
if (p1.isPresent()) {
    if (p2.isPresent()) {
        result = myObject.calculateSomething(p1, p2);
    } else {
        result = myObject.calculateSomething(p1);
    }
} else {
    if (p2.isPresent()) {
        result = myObject.calculateSomething(p2);
    } else {
        result = myObject.calculateSomething();
    }
}

そこで質問ですが、なぜバッドプラクティスとして Optional をメソッドの引数として使用することができますか (解決策 1 を参照)? 私にとっては最も読みやすい解決策に見えますし、将来のメンテナにとってパラメータが空/nullになりうることが最も明白になります。 (私は Optional これは戻り値としてのみ使用されることを意図していますが、このシナリオで使用しない論理的な理由は見当たりません)。

どのように解決するのですか?

ああ、そういうコーディングスタイルは、ちょっと塩梅がいいんですよ。

  1. (+) Optionalの結果を意味解析せずに他のメソッドに渡すこと; メソッドに任せることは、全く問題ありません。
  2. (-) メソッド内部で条件ロジックを引き起こすOptionalパラメータを使用することは、文字通り逆効果です。
  3. (-) 引数を Optional に入れる必要があるのは、コンパイラにとって最適とは言えず、不必要な折り返しをしてしまいます。
  4. (-) null可能なパラメータと比較して、Optionalはよりコストがかかる。
  5. (-) 実際のパラメータで、誰かが Optional を null として渡す危険性がある。

一般的には オプショナルは2つの状態を統合し、それを解かなければならない。したがって、データフローの複雑さのために、入力よりも結果に適しています。