2012-03-18 9 views
23

でヌルチェック対時々私は私が試みは、java

public void printIt(Object1 a){ 
    if (a!=null){ 
    SubObject b= a.getB(); 
    if (b!=null){ 
     SubObject2 c=b.getC(); 
     if(c!=null){ 
      c.print(); 
     } 
    } 
    } 
} 

ときI(通常はそれがあればより多くのネストされた、より複雑な構造を持っていますが、例えばenoughtである)このようなコードの一部を記述する必要があります直面しています何もしない、アプローチは、パフォーマンスや問題の他の種類のように、この二番目の形式で何か問題があるの

public void printIt(Object1 a){ 
    try{ 
     a.getB().getC().print(); 
    }catch (NullPointerException e) { 
    } 
} 

何ができるかが失敗したと何かがnullであるかどうかを知る必要がありいけませんか?

ありがとう

+8

例外を念頭に置いて、標準的なプログラムの流れで設計されていない、彼らは例外的な状況のために設計されています。 –

+2

可能な複製:http://stackoverflow.com/questions/8621762/java-if-vs-try-catch-overhead – blackcompe

+0

'RunTimeException'をキャッチしないで、代わりにそれを避けてください。 –

答えて

14

例外的なバージョン(Groovyのセーフ・ナビゲーション・オペレータ?.を使用しているチェーンに似ています)では、Demeterの法則(DemeterのStrongly-Worded Suggestion)を使用して、 。

同様に、深くネストされたコードは読みにくく、その下にはすべて同じ "違反"が存在し、そのような方法の循環的複雑さは高いです。

public void printIt(Object1 a) { 
    if (null == a) { 
     return; 
    } 

    SubObject b = a.getB(); 
    if (null == b) { 
     return; 
    } 

    SubObject2 c = b.getC(); 
    if (null == c) { 
     return; 
    } 

    c.print(); 
} 

私はむしろチェックをカプセル化し、ほとんど完全に質問の必要性を排除し、適切な場所でLAMS(リトル補助メソッド)を参照してくださいね。

+0

あなたは私にそれを打つ!副次的なものとして、理論的なa、b、cが決してnullにならない方法があると確信しています。異なったコーディングのケースです。 –

7

はい。 2番目のバージョンはひどい性能を持つでしょう。

通常の制御フローでは例外を使用しないでください。効果的なJava項目57:例外的な状況に対してのみ例外を使用する。

== UPDATE ==

でもパフォーマンスの問題を無視して(例外は私のbenchmarkによると、彼らはかつてよりも高速ですが、ありませんほぼ同じ速チェックするとシンプルのように)、それは本当にコード臭い使用しますこのような標準プログラムフローの例外。 JVMバイトコードは、ifステートメントでも、ヌルチェックのために特別な最適化を行うことができます。第1のコードサンプルが非常に好ましい。

+6

それは単に真実ではありません。 Javaの例外は、これまで経験していたパフォーマンスの低下を招くことはありません。 –

+0

引用してください。 (そして、どのJavaバージョン?別の方法で示した最近のベンチマークを行ったことがあります) –

+0

また、例外が以前より大幅に高速であったとしても、基本的な 'if'チェックと同じくらい速いのであれば、かなり驚くでしょう。 –

7

2番目のバージョンの最も間違った部分は、NPEがgetB()の内部で発生した場合、それは暗黙のうちに無視されます。getC()すでに述べたように、例外は例外的なケースです。

2

メカニズムをどの程度遅くしていたとしても、例外を使用することは、パフォーマンスに関して常に悪い考えです。例外がスローされるたびに、完全なスタックが展開されてスタックトレースが作成されます。したがって、Lois Wasserman氏のように、(通常の)プログラムフローではなく、例外的な場合にはそれらに頼るべきではありません。

ネストされたIFSは次のように追加の情報を印刷する機能「Bがnullである」美の定義ではありませんが、あなたを与えるなど

+0

実際はexception throw/catchを最適化することができるので、パフォーマンスは必ずしも悪くはありません(それに頼ることは望ましくないかもしれませんが)。 –

2

答えは使用バージョンA.

あるそれはありますフロー制御の例外を使用するには、一般に「不良設計」と見なされます。例外は例外的なもので、特にヌルチェックを使用して完全に回避できるNPEです。さらに、ヌルチェックを使用すると、という用語がヌルであることを伝えることができます(ヌルがバージョンBでどこにあるかわかりません)。

パフォーマンスはではありません。ではそれ以上の例外は発生しません(スタックトレースは使用する場合にのみ作成されます)。それはクリーンなコードの問題です。

しかし、あなたの入力がそうでないと呼ぶ前に妥当な方法を伝えることができないため、フロー制御の例外を避けることはできません。たとえばSimpleDateFormat.parse()から送出された例外があります。構文解析可能な。

7
public void printIt(Object1 a){ 
    if(a==null){ 
     throw new IllegatArgumentException("a was null, but this is not allowed here."), 
    } 
    [...] 

高速で失敗して失敗します。 shoudがnullでない場合、Exceptionをスローします。これにより、コードがより安定して確実になります。

あなたのa)とb)の間で決めなければならない場合は、a)を選択します。しかし、そこにnullを入れてはいけない場合は、エラー状況を隠すでしょう。

1

コードには、チェックされていない例外の例外ハンドラを含めないでください。ヌルになる可能性があるオブジェクト参照には常にヌルチェックを使用する必要があります。

呪い

2

確かに(A)が、あなたは前の回答で述べたようにif文を入れ子避けるための方法を再構築する必要があります。例外は一度のパフォーマンスヒットではありませんが、まだのヌルチェックよりも遅く、このようなプログラムフロー制御には使用しないでください。オブジェクトがnullの場合はチェックする必要がありますが、許可されていない場合は、オブジェクト参照を割り当てた時点で失敗する必要があります。多くの状況では、ヌルを避けるためにデフォルト実装(空のリストは良い例です)を持つことができます。その結果、より洗練されたコードが得られます。可能な限り、ヌルを避けてください。

0

Java 8に移行する場合は、OptionalとLambdasを使用できます。まず、あなたはそれぞれのタイプのOptionalを返すために、あなたのクラスを書き換える必要があります。

class Object1 { 
    private SubObject b; 

    Optional<SubObject> getB() { 
     return Optional.ofNullable(b); 
    } 
} 

class SubObject { 
    private SubObject2 c; 

    Optional<SubObject2> getC() { 
     return Optional.ofNullable(c); 
    } 
} 

class SubObject2 { 
    @Override 
    public String toString() { 
     return "to be printed"; 
    } 
} 

さて、あなたは簡潔な方法でNullPointerExceptionsがリスクなしで呼び出しチェーンことができます。

a.getB() 
    .flatMap(SubObject::getC) 
    .ifPresent(System.out::println); 

がOracleの記事を参照してください。詳細については、Tired of Null Pointer Exceptions? Consider Using Java SE 8's Optional!を参照してください。オプションのJava 8を使用して

0

Optional.ofNullable(a) 
      .map(Object1::getB) 
      .map(SubObject::getC) 
      .ifPresent(Object2::print); 
関連する問題