ケース内のオブジェクトまたはJava 8およびJava 9のオプション。パート1:「それなしで生きる方法」

ケース内のオブジェクト



おそらく、内部開発の法則に従って、または外部条件に応じて構造を変更するオブジェクトをすでに処理しなければならなかったでしょう。 実際には、これは、外部世界のオブジェクトの一部にアクセスできる場合とできない場合があることを意味します。

これらはどのようなオブジェクトになりますか? 多くのサービス会社、取引企業、銀行は、時刻に応じてさまざまなタイプのサービスを提供しています。 異なるデバイスは、その状態に応じて特定のアクションを実行する場合と実行しない場合があります。 スマートフォンまたはラップトップの画面からこのテキストを読んだ場合、バッテリーの充電が特定の制限を下回った場合、表示を停止することがあります。

このチュートリアルのこの記事と以降の記事では、動的構造を持つ単純なオブジェクト、Optionalクラスのメソッドを使用してJavaでそれらをモデル化して使用する方法について説明します。

Habréを含むロシア語を含む、このクラスのメソッドの使用について多くのことが書かれています。 この一連の記事では、問題をより広く見て、問題に対する選択されたソリューションの利点と欠点、および代替アプローチを検討します。

このシリーズの最初の記事では、JavaでOptionalを使用せずにNullPointerExceptionを使用する方法について説明します。 Optionalなしでも生きることができることを願っていますが、それで生活がもっと楽しくなるはずです。 このシリーズの2番目の記事では、Java 8に登場したOptionalクラスのメソッドについて説明し、 3 番目の記事では 、Java 9で追加されたクラスのメソッドについて説明します。 5番目の記事では、クラス内でOptionalを使用する場所について説明し、要約を読んで、シリーズを最後まで読んだすべての読者に貴重な贈り物を贈ります。



それでは、最初のデバイスである単純なコーヒーマシンなど、動的な構造を持つ要素へのアクセスをJavaで実装する方法について説明しましょう。

デバイスの物理構造は時間とともに変化しないことにすぐに注意してください。 構造のダイナミクスについて言えば、ユーザーの目を通してデバイスを見ます。 何らかの理由でデバイスがユーザーのコーヒーを準備できない場合、この機能は現時点では実際には使用できません。

Javaを使用してこれをどのように表現できますか?

このようなデバイスの制御ユニットを作成するタスクが与えられ、次のような関数が必要だとします

device.getCoffeePortion()
      
      





このメソッドはどのタイプの要素を返す必要がありますか? 実際、デバイスがユーザーにコーヒーを提供できる場合とできない場合があります。

この問題を解決する方法はあまりありません(少なくとも私は知っています)。



オブジェクトまたはnullを返します



最も一般的な解決策は、正の場合はオブジェクトを返し、負の場合はnullを返すことです。 したがって、ユーザーは常に戻り値を確認し、それがnullでない場合にのみ使用する必要があります。

問題は、オブジェクトのユーザーが何らかの方法でnullオブジェクトを返す可能性を知っているか推測しなければならないことです。 自分のコードでメソッドを呼び出すプログラマーは、チェックやリストへの書き込みなどを行わずに、他の関数の呼び出しのチェーンのパラメーターとして渡すことができます。場所。

NullPointerExceptionは、Javaプログラマーのエラーの中でも、検索と除去に費やされた時間と神経の両方で悪名高いチャンピオンです。

この大惨事には、「10億ドルの間違い」と呼ばれる著者がいることに注意してください。 Nullは、ALGOL言語の開発時に1965年にJavaよりもずっと早く登場しました。

44年後、このモンスターの作者である(素晴らしい科学者でもある)トニー・ホアは彼の記事「Null References:The Billion Dollar Mistake」(QCon、2009年8月25日 )に次のように書いています

私はそれを10億ドルの間違いと呼んでいます...私の目標は、参照のすべての使用が絶対に安全であることを確認することであり、コンパイラによって自動的にチェックが実行されました。 しかし、実装が非常に簡単だったという理由だけで、null参照を挿入する誘惑に抵抗することはできませんでした。 これにより、無数のエラー、脆弱性、およびシステムクラッシュが発生し、過去40年間で数十億ドルの痛みと損害を引き起こした可能性があります。


オブジェクトの作成者は、注釈付きの戻り結果を使用して、状況を多少緩和できます。次に例を示します。

 @Nullabble CoffeePortion getCoffeePortion()
      
      





プログラマーが最新のIDEを使用する場合、特定の状況では、ヌルオブジェクトをチェックする必要があることを彼に示します。 しかし、これは常に起こるわけではなく、それを当てにする価値はありません。

したがって、操作の結果としてnullを返すのは悪いことです。 したがって、これを回避する必要があります。 そしてどうやって?



最初によく尋ねる



解決策の1つは、各get ...メソッドにコンパニオンが持つ...を提供することです...オブジェクトのユーザーは、getリクエストの前に...返される値があるかどうか尋ねる必要があることを何らかの方法で警告する必要があります この場合、ペアは次のようになります。

 boolean hasCofeePortion() CoffeePortion getCoffeePortion()
      
      





最初の関数がtrueを返した場合、関数メイトを呼び出すためのゴーアヘッドを提供します。 ユーザーは、理論的には最初のhas ...関数を呼び出さないようにすることができます。 呼び出し時の値が使用できない場合、get ...関数は最初のオプションのようにnullを返しませんが、例外をスローします。

したがって、コールチェーンに沿って「危険な」オブジェクトを転送する問題はなくなります。 これがこのアプローチの利点です。 しかし、このアプローチには2つの重大な欠点があります。 まず、関数の数が乗算されます。 第二に、呼び出しの時点で...オブジェクトが利用可能であり、取得するまでに...が利用できなくなったという保証はありません。 (この単純な例ではこれは不可能ですが、オブジェクトの状態が時間または外部の影響に依存し、get ...呼び出しを準備するために他の操作が必要な複雑なシステムでは、この危険は現実です。

そのため、最初に質問してからそれを取ることは、良い戦略ではありません。 しかし、その逆ではありませんか? このアイデアは、次のアプローチで使用されます。



オブジェクトは常に発行されますが、常に生きているわけではありません。



このアプローチでは、オブジェクトは常に戻りますが、追加の属性が含まれます。 この記号は、大まかに言って、実際にそうであるかどうかを示しています。 極端な例を指すと、このアプローチは次のように定式化できます。生き物またはその死体を取得します。 しかし、それが死体であっても、彼は少し話しています。

つまり、このアプローチでは、isActive()やisPresent()などのメソッドを恐れることなくいつでも呼び出すことができるということです。 「死んだ」オブジェクトですら。 そして肯定的な答えで、オブジェクトをさらに操作します。

このアプローチの明らかな欠点は、独自の機能(ビジネスロジック)の観点から説明できない技術的機能のオブジェクトにかかっていることです。 特定の状況では、この機能はこのロジックと競合する場合があります。 たとえば、オブジェクトが他の2つのオブジェクトに関連付けられているとします。 1つのオブジェクトの観点からは、アクティブまたは「生きている」ことができ、別のオブジェクトの観点からは「死んでいる」ことができます。

ただし、技術的な観点からは、このアプローチには独自の、場合によっては予期しない利点があります。 たとえば、JSONまたはXMLの形式で複合オブジェクトを保存または送信する必要がある場合、現在非アクティブ化されている部分を含めて、全体を送信するのが合理的です。 結局、オブジェクト(ファイルまたはストリームからの読み取り)を復元した後、非アクティブ化された部分をいつかアクティブ化する必要があることが判明する場合があります。

したがって、このアプローチはNullPointerExceptionをスローせず、「偽物」であるという点で優れています。 同様のものを見つけることは可能ですが、説明されている欠点はありませんか?



空のシートが返されます



Java 8 Optional以前の専門家による最も推奨されるアプローチの1つは、以下に説明するアプローチでした。

彼のアイデアは非常にシンプルです。 オブジェクトの代わりに、オブジェクトの配列またはリストを返します。 この配列またはリストは、空にするか、オブジェクトを1つだけ含めることができます。

実際、リストを処理する関数を呼び出した直後に、メソッドのユーザーを強制的に配置します。 このリストを他のメソッドのパラメーターとしてさらに渡すことはほとんどありません。

get ...の状況は大きく変化し始めます...メソッドは、int、既知のオブジェクト、条件付きで存在するオブジェクトなどの基本値を返します。

そして、この矛盾を克服するため、およびその他の理由で、Java開発者はOptionalを導入することを決定しました。 このクラスの長所と短所については、このシリーズの以下の記事で説明します。



次の記事に進みます。



イラスト: ThePixelman



All Articles