2013-10-28 3 views
7

コードでは、チェーンメソッドがたくさんあります。たとえば、obj.getA().getB().getC().getD()です。メソッドgetD()がnullではないが、その前にすべての以前のgetterをチェックする必要があるかどうかを調べるヘルパークラスを作成したいと思います。私はこの方法でそれを行うことができます。メソッドチェイン内の最後のゲッターがヌルでないかチェックしてください。

try { 
    obj.getA().getB().getC().getD(); 
} 
catch (NullPointerException e) { 
    // some getter is null 
} 

か(「愚か」である)

if (obj!null && obj.getA()!=null && obj.getA().getB()!=null && ...) { 
    obj.getA().getB().getC().getD(); 
} 
else { 
    // some getter is null 
} 

を、私は私のコードでtry{} catch()を使用して、それを毎回チェックする必要はありません。この目的のための最良の解決策は何ですか?

私は最高のだろうと思います。

  1. obj.getA().getB().getC().getD().isNull() - この目的のために、私はisNull()メソッドが含まれているいくつかのインターフェイスを実装例えば、私のゲッターのすべてを変更する必要があります。
  2. NullObjectHelper.isNull(obj.getA().getB().getC().getD()); - これは最高です(私はそうだと思いますが)どのようにこれを実装するのですか?
+5

解決策。リファクタリング#LawOfDemeter – user802421

+1

@ user802421連鎖しないでください。アプリケーション全体をリファクタリングする必要はありません。私がしたいのは、いくつかのヘルパークラスを作成することだけです。私はリファクタリングが一番良いと思っていますが、時間がありません。 – pepuch

+0

あなたの2つの "解"が中間結果が 'ヌル 'であるのに役立つのはわかりません – Henry

答えて

7

Optionパターンで結果を得ることができます。これにより、メソッドのシグネチャを変更することが強制されますが、基本的には、メソッドがあるタイプのTを返す場合はnull以外の値が返され、Option<T>を返す場合は値Tまたはnullが返されます。

Java 7にはnull安全性という機能がありましたが、最終リリースから削除されました。あなたは何ができる:

obj?.getA()?.getB()?.getC()?.getD() 

をので、あなたが安全にそれを行うだろう。また、Javaの8はOptionalと呼ばれる機能が追加されます。

実際に今すぐ使用したい場合は、Null Objectパターンを試してください。つまり、nullを返す代わりに、のデフォルト値の値を返すことができ、NullPointerExceptionをトリガーしません。あなたはユーティリティがそれをしたい場合は、いくつかの機能インタフェースでそれをラップし、それを呼び出すことができます:しかし、あなたはあなたのゲッターにいくつかの変更

class Object { 
    A getA() { 
    // ... 
    return a == null ? A.NULL : a; 
    } 
} 

class A { 
    static A NULL = new A(); // some default behaviour 
    B getB() { 
    if (this == NULL) return B.NULL; 
    // ... 
    return b == null ? B.NULL : b; 
    } 
} 

EDITを追加する必要があります。

static boolean isNullResult(Callable call) throws Exception { 
    try { 
     return call.call() == null; 
    } catch (NullPointerException npe) { 
     return true; 
    } 
} 

使用方法は、次のようになります。

isNullResult(new Callable<Integer>() { 
    @Override 
    public Integer call() throws Exception { 
     return new A().getB().getC().getInt(); 
    } 
}); 

既存の機能すでに述べた

+0

+1おかげで提案のためのmishadoff。私は 'Null object'パターンを使うことができることを知っていますが、もし私がそれを使うなら、私はアプリケーションにいくつかの変更を加える必要があります。アプリケーションはほぼ完成しており、私はこのプロジェクトで新しくなっているので、やりたいとは思わない。 – pepuch

+0

@pepuchユーティリティー使用のための更新された解決策を参照 – mishadoff

1

として、真の解決策は、リファクタリングあるを変更する必要はありません。一方

、あなただけの機能では、あなたの最初の回避策包むことができます:発信者サイトで

static D getD(MyClass obj) { 

    try { 
     return obj.getA().getB().getC().getD(); 
    } 
    catch (NullPointerException e) { 
     return null; // Or even better, some default D 
    } 
} 

を:

D d = getD(obj); 

少なくとも、あなたが発信者をゴミ箱にする必要はありませんtry-catchブロックを使用します。 getX()呼び出しの一部がnullを返し、dnull.になると、エラーを何らかの形で処理する必要があります。ラッパー機能でデフォルトのDを返すのが最適です。


私は中間getX()のいずれかがnullを返した場合、あなたの質問の最後にリスト2つのオプションが役立つだろうどのように表示されません。 NullPointerExceptionが表示されます。

+0

最後の例でNPEを避けるために、Runnableブロックにコードをラップし、後でtry-catchで呼び出すことができます。 – mishadoff

+0

実際に使用したコードはまったくお勧めしません。通常、AまたはBまたはCがnullの可能性があるように聞こえるので、この場合は例外をスローするという犠牲を払うのは一般的には悪い考えです。実用的な方法で物を包むことは確かに良いアプローチです。しかし、私はむしろユーティリティメソッドには、怠け者で例外をキャッチするのではなく、ヌルチェックを行う「ばかげた」コードが含まれていました。 –

+0

@AndrzejDoyle **そして、私は最初にリファクタリングをお勧めします。**潜在的にnullのオブジェクトと連鎖したgetterは欠陥の兆候です。 "愚かな"コードの私の問題は、エラーが発生しやすいということです。そこにタイプミスをしたり、ヌルチェックを見逃したりするのは簡単です。私たちはtry-catchと "愚か"コードをリファクタリングして、それらのどれも必要ないようにすることです...ラッパー関数(try-catchか "ばかげた"スニペットが使用されるかどうかは関係ありません)は、新しいコード*比較的*クリーン;それが私の主張です。 – Ali

2

あなたはゲッターチェーンにnullを処理するためにOptional.isPresentOptional.orElseのようなメソッドを使用できるJava 8の通り:

boolean dNotNull = Optional.ofNullable(obj) 
       .map(Obj::getA) 
       .map(A::getB) 
       .map(B::getC) 
       .map(C::getD) 
       .isPresent(); 

これは、このアプローチの欠点NullPointerExceptionがをキャッチすることが好ましいものののためのオブジェクトの割り当てでありますオプションインスタンス。

このオーバーヘッドなしで同様の動作を行う独自の静的メソッドを記述することが可能である:

boolean dNotNull = Nulls.isNotNull(obj, Obj::getA, A::getB, B::getC, C::getD); 

サンプル実装については、Nullifierタイプhereを参照してください。

ないアプローチは、ネストされた場合-nullでないチェックより大きいランタイム効率を持っている可能性があります。

関連する問題