web-dev-qa-db-ja.com

オブジェクト階層のナビゲート中のnullチェック

小さなオブジェクト階層をトラバースして値を取得し、TextViewオブジェクトに表示するコードを実装する必要がありました(これはAndroid/Javaです)。これを行う必要がありました6回でオブジェクト階層のさまざまな値に6 TextViewsを入力します。

私の実装は実装Bでした。しかし、レビューの結果、私の同僚は反対し、実装Aが適切であると確信しました。私のバージョンはよりクリーンであるだけでなく、開発者として何かを簡単に見逃す可能性があるため、エラーが発生しにくいと私は信じています。

これらの実装の両方の長所と短所について、ご意見をお聞かせください。

実装A:

if (house != null && house.getLounge() != null && house.getLounge().getLetter() != null)
{
    String myValue = house.getLounge().getLetter();
    textView.setText(myValue);
}
else
{
    // Do nothing, or maybe make textView hidden.
}

実装B:

try
{
    String myValue = house.getLounge().getLetter();
    textView.setText(myValue);
}
catch (NullPointerException e)
{
    // Do nothing, or maybe make textView hidden.
}
3
Eurig Jones

あなたが与えたシナリオを考えると、私は実装Aに行きます。

どちらの実装でも、housenullまたはhouse.getLounge()またはhouse.getLounge().getLetter() return nullである場合が処理されます。

実装Bの1つの問題は、呼び出されたメソッドのいずれかでcouldが発生するNullPointerExceptionを、abnormalの発生である正常なものとして処理することです。コメンターが指摘したように、それは例外を「飲み込む」。 todayの時点で、呼び出されたメソッドがNullPointerExceptionを発生させないことが証明できれば、それは問題ではありません。コードの変更、エラーの導入、私たちがそうであると私たちが思ったのは、実際にはそうではない、など.

実装Bもロジックを覆い隠しています。実装Aを見ると、開発者がhousenullになるのを防いだことなどは明らかです。「何もしない」ブランチが発生する条件のセットは取りました。実装Bでは、NullPointerExceptionになる条件のセットは何ですか? getLoungeは時々NullPointerExceptionをレイズしますか?私は他の場所を見なければ分からない。

4
Louis

Aの利点

あなたは何をしたいかconditionの下で明確にします:

_house != null && house.getLounge() != null && house.getLounge().getLetter() != null
_

それが条件です。そして、ある値をget、もう1つの値をsetしたいとします。

_String myValue = house.getLounge().getLetter();
textView.setText(myValue);
_

intentの通信に関しては、これはclearです。ところで2番目の条件は必要ありません。文字列がnullの場合、何も表示されません。

Bが間違っている理由:

_try-catch_を使用して通信します。"xを実行したいのですが、これはなんとなく危険です"-それは実際にはそうではありません。あなたの意図はAの下ほど明確ではありません。そして-私の目には悪い-あなたはエラーの可能性を不明瞭にします:

_String myValue = house.getLounge().getLetter();
textView.setText(myValue);
_

NullPointerExceptionがスローされるのは、a)getLounge()nullを返した場合、b)textViewがnullの場合です。あなたはoneNPEをキャッチしているので、どれがどれかわかりません。もちろん、このような単純なケースでは、debugにするのは簡単ですが、これは一般に間違った方法です

私は3番目の方法に賛成です:

_String myValue = (house.getLounge()!=null)?house.getLounge().getLetter:"";
_

もちろん、_ternary Operator_(一部の言語は概念を放棄しました)の使用についてDiskussionがありますが、この場合は最適です:デフォルト

3
Thomas Junk

別のオプション

import Java.util.Optional;

Optional.fromNullable(house)
               .map(House::getLounge)
               .map(Lounge::getLetter)
               .ifPresent(letter -> textView.setText(letter));

これにより、フロー制御の例外の使用が回避されますが、可能な各nullの詳細な処理も回避されます。代わりに、そのロジックはオプションのマップロジックの一部です。

3
Winston Ewert
  1. バージョンAは自己記述型です。それはまさにそれが言うことをすることを目指しています。コンテキストから外されたバージョンBを見ると、防御がnullであるかtextFieldnullであることに反対するものであるかどうかはわかりません(おそらく、一部のレイアウトでは使用できず、他の一部のレイアウトでは使用できません-Androidリソース)を扱う場合、これは奇妙なことではありません。

  2. レイアウトファイルにいくつかのタイプミスが導入されたため、ある日textFieldnullである場合(長期的にはかなり可能性があります-findViewById return null if itは見つかりません)-バージョンAはエラーを明確にし、役立つ例外をスローします。そして、バージョンBはエラーを隠し、簡単な間違いを本当にあいまいでよく隠されたバグにします。

  3. バージョン "b"について唯一言えることは、53文字短いということです。これはwayにして、適切な選択にするためのものです。

0
fdreger