変数をnullチェックするよりも優先的にオプションを使用するのはなぜですか?


25

2つのコード例を取り上げます。

if(optional.isPresent()) {
    //do your thing
}

if(variable != null) {
    //do your thing
}

私の知る限り、最も明らかな違いは、オプションでは追加のオブジェクトを作成する必要があるということです。

ただし、多くの人がオプションを急速に採用し始めています。オプションを使用する場合とnullチェックを使用する場合の利点は何ですか?


4
isPresentを使用することはほとんどないため、通常はifPresentまたはmap
jk

6
@jk。そのためif文があるすっごく過去十年間、誰もが今モナドの抽象化とラムダを使用しています。
user253751

2
@immibis私はかつてこのトピックについて別のユーザーと長い議論をしていました。ポイントは、if(x.isPresent) fails_on_null(x.get)あなたが型システムを終了し、条件と関数呼び出しの間の(明らかに短い)距離でコードが「頭の中で」壊れないという保証を維持する必要があるということです。でoptional.ifPresent(fails_on_null)型システムあなたのためにこれを保証するもので、あなたが心配する必要はありません。
ziggystar

1
Javaの使用Optional.ifPresent(およびその他のさまざまなJava構成体)の主な欠点は、最終変数のみを効果的に変更でき、チェック済み例外をスローできないことです。ifPresent残念ながら、これはしばしば回避するのに十分な理由です。
マイク

回答:


19

Optionalそうでなければ、頭の中ですべてを行わなければならない作業を行うために型システムを利用しますnull。与えられた参照がであるかどうかを覚えています。これはいい。コンパイラに退屈なドラッグワークを処理させ、創造的で興味深い仕事のために人間の思考を確保することは常に賢明です。

なしOptionalでは、コード内のすべての参照は不発弾のようなものです。それにアクセスすると、何か役に立つことがあります。そうでなければ、例外でプログラムを終了するかもしれません。

Optionalがあり、なしのnull場合、通常の参照へのすべてのアクセスは成功し、オプションへのすべての参照は、設定されていないか確認しない限り成功します。これは保守性において大きな勝利です。

残念ながら、現在提供されOptionalているほとんどの言語は廃止されていないnullため、「絶対に絶対にない」という厳格なポリシーを制定することによってのみコンセプトから利益を得ることができますnull。したがって、OptionalたとえばJavaは理想的なほど魅力的ではありません。


将来的にはこれを読んで、誰のために(私の答えを参照してください) -あなたの答えは、トップ1であるので、それは価値が利点としてラムダの使用を追加するかもしれない
ウィリアム・ダン

最近のほとんどの言語では、Kotlin、Typescript、AFAIKなどのnullを許可しない型が提供されています。

5
IMOこれは、@ Nullableアノテーションを使用してより適切に処理されます。Optional値がnullになる可能性があることを思い出させるためだけに使用する理由はありません
-Hilikus

18

Optional他の回答がカバーしてきたように、失敗する可能性のある操作に強い型付けをもたらしますが、それはあるはるかに最も興味深いまたは価値のあるものからOptionals、テーブルに持って来ます。はるかに便利なのは、失敗のチェックを遅らせたり、回避したり、失敗する可能性のある多くの操作を簡単に構成できることです。

あなたが持っていた場合を検討しoptional、あなたのコード例から変数を、あなたはそれぞれのかもしれないが、潜在的に失敗する二つの追加手順を実行する必要がありました。途中のステップが失敗した場合、代わりにデフォルト値を返します。Optionals正しく使用すると、次のような結果になります。

return optional.flatMap(x -> x.anotherOptionalStep())
               .flatMap(x -> x.yetAnotherOptionalStep())
               .orElse(defaultValue);

null私は3回をチェックしなければならなかっただろうnullコードに複雑さとメンテナンスの頭痛の多くを追加した、先に進む前に。 OptionalsそのチェックをflatMapおよびorElse関数に組み込みます。

注:isPresent一度も呼び出しませんでした。これは、を使用するときにコードの匂いとして考える必要がありますOptionals。それは必ずしもあなたがすべきという意味ではありません決して使用しないでisPresent良い方法があるかどうかを確認するために、あなたは大きくありません任意のコードを精査すべきであるだけであること、。そうでなければ、あなたは正しいです、あなたはを使用するよりもわずかな型安全性の利益を得ているだけですnull

また、コードの他の部分を中間結果からのNULLポインターから保護するために、このすべてを1つの関数にカプセル化することについてはあまり心配していないことに注意してください。.orElse(defaultValue)たとえば、別の関数を使用する方が理にかなっている場合、そこに配置することに対する不安がはるかに少なくなり、必要に応じて異なる関数間で操作を構成するのがはるかに簡単になります。


10

有効な応答としてのnullの可能性を強調しており、人々はしばしば(正しいか間違って)返されないだろうと考えています。nullが有効な場合に数回強調表示すると、無意味なnullチェックの膨大な数でコードを散らかすことを省略できます。

理想的には、変数をnullに設定すると、オプション以外のどこでもコンパイル時エラーになります。ランタイムNULLポインター例外を排除します。明らかに、後方互換性はこれを排除しますが、悲しいことに


4

例を挙げましょう。

class UserRepository {
     User findById(long id);
}

この方法が何を目的としているのかは明らかです。しかし、リポジトリに特定のIDのユーザーが含まれていない場合はどうなりますか?例外をスローするか、nullを返しますか?

2番目の例:

class UserRepository {
     Optional<User> findById(long id);
}

ここで、指定されたIDのユーザーがいない場合、ここで何が起こりますか?右、Optional.absent()インスタンスを取得し、Optional.isPresent()で確認できます。Optionalを使用したメソッドシグネチャは、その契約についてより明示的です。メソッドがどのように動作するかはすぐにわかります。

また、クライアントコードを読み取るときに利点があります。

User user = userRepository.findById(userId).get();

.get()が即座にコードの匂いとして見えるように目を訓練しました。クライアントは、呼び出されたメソッドのコントラクトを意図的に無視することを意味します。これはOptionalなしよりもはるかに簡単です。その場合、呼び出されたメソッドのコントラクトが何であるか(nullが許可されているかどうかに関係なく)すぐには分からないため、最初にチェックする必要があるためです。

Optionalは、戻り値型がOptionalのメソッドがnullを返さないという規則で使用され、通常、Optional戻り型のないメソッドはnullを返さないという(あまり強くない)規則でも使用されます(ただし、@ Nonnull、@ NotNull、または同様のアノテーションを付ける方が良いです) 。


3

Optional<T>使用すると、メソッドの有効な応答/戻り値として「失敗」または「結果なし」にすることができます(たとえば、データベース検索など)。失敗/結果なしを示すために使用するOptional代わりにを使用すると、nullいくつかの利点があります。

  • 「失敗」オプションであることを明確に伝えています。メソッドのユーザーは、null返される可能性があるかどうかを推測する必要はありません。
  • 値はnull、少なくとも私の意見では、すべきではないセマンティクスは完全に明確ではないかもしれないと何を示すのに使用されます。以前に参照されたオブジェクトが収集される可能性があることをガベージコレクターに伝えるために使用する必要があります。
  • このOptionalクラスは、値を条件付きで処理する(例:)、ifPresent()または透過的な方法でデフォルト値を定義する(orElse())ための多くの素晴らしいメソッドを提供します。

残念ながら、オブジェクト自体がまだある可能性があるためnull、コードのチェックの必要性を完全に削除するわけではありOptionalませんnull


4
これは本当にOptionalの目的ではありません。エラーを報告するには、例外を使用します。それができない場合は、結果またはエラーコードのいずれかを含む型を使用してください
ジェームズヤングマン

私は強く反対します。Optional.empty()は、私の意見で失敗または存在しないことを示す素晴らしい方法です。
-LegendLength

@LegendLength、失敗した場合には強く反対しなければなりません。関数が失敗した場合、それはより良い私の説明だけではなく、空を与えるだろう、「私は失敗しました」
ウィンストンエバート

申し訳ありませんが、検索中に「x」という名前の従業員が見つからないなど、「予想される失敗」を意味します。
-LegendLength

3

他の回答に加えて、クリーンなコードを記述する際のOptionalsのその他の主な利点は、以下に示すように、値が存在する場合にLambda式を使用できることです。

opTr.ifPresent(tr -> transactions.put(tr.getTxid(), tr));

2

次の方法を検討してください。

void dance(Person partner)

それでは、呼び出しコードを見てみましょう。

dance(null);

これは、dancenullを予期していなかったため、クラッシュの追跡が困難になる可能性があります。

dance(optionalPerson)

ダンスは期待していたので、これは、コンパイルエラーが発生しPersonていませんOptional<Person>

dance(optionalPerson.get())

私が人を持っていなかった場合、これはこの行で例外を引き起こします。私が違法にOptional<Person>人に変換しようとした時点です。重要なのは、nullを渡すのとは異なり、例外はここへのトレースであり、プログラム内の他の場所ではありません。

まとめると、オプションを誤用すると問題を追跡しやすくなり、nullを誤用すると問題を追跡しにくくなります。


1
Optional.get()コードの呼び出しが不適切な場合に例外をスローする場合Optional.isPresent()は、OPに示されているように、最初にチェックせずにOptional.getを呼び出すことはほとんどありませんoptionalPersion.ifPresent(myObj::dance)
クリスクーパー

@QmunkE、はい、optionalが空でないことが既にわかっている場合(isPresentを呼び出したため、またはアルゴリズムがそれを保証するため)、Optional.get()を呼び出す必要があります。ただし、isPresentを盲目的にチェックし、存在しない値を無視して、追跡するのが面倒なサイレント障害のホストを作成することを心配しています。
ウィンストンユワート

1
私はオプションが好きです。しかし、実際のコードでは、単純な古いヌルポインターが問題になることはほとんどありません。ほとんどの場合、問題のあるコード行の近くで失敗します。そして、このテーマについて話すとき、それは人々によって誇張されると思います。
-LegendLength

@LegendLength、私の経験では、ケースの95%は、NULLがどこから来たかを特定するために実際に容易に追跡可能です。ただし、残りの5%は追跡が非常に困難です。
ウィンストンイーバート

-1

Objective-Cでは、すべてのオブジェクト参照はオプションです。このため、投稿したようなコードは馬鹿げています。

if (variable != nil) {
    [variable doThing];
}

上記のようなコードはObjective-Cでは前代未聞です。代わりに、プログラマーはただ:

[variable doThing];

場合はvariable値が含まれている、そしてdoThingそれに呼び出されます。そうでなければ、害はありません。プログラムはそれをノーオペレーションとして扱い、実行を続けます。

これはオプションの真の利点です。でコードを散らかす必要はありませんif (obj != nil)


それはただ静かに失敗する形ではありませんか?場合によっては、値がnullであることを気にして、それについて何かをしたいかもしれません。
-LegendLength

-3

if(optional.isPresent()){

ここで明らかな問題は、「オプション」が本当にあればということです欠落している(つまり、nullである)場合、nullオブジェクト参照のメソッドを呼び出そうとするNullReferenceException(または同様の)でコードが爆発することです。

次のように、特定のオブジェクトタイプのNULLネスを決定する静的なヘルパークラスメソッドを作成することができます。

function isNull( object o ) 
{
   return ( null == o ); 
}

if ( isNull( optional ) ) ... 

または、おそらく、より便利に:

function isNotNull( object o ) 
{
   return ( null != o ); 
}

if ( isNotNull( optional ) ) ... 

しかし、これらのどちらかが実際にオリジナルよりも読みやすく、理解しやすく、保守しやすいのでしょうか?

if ( null == optional ) ... 
if ( null != optional ) ... 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.