!= nullステートメントの回避


4015

object != null避けるためにたくさん使いますNullPointerException

これに代わるものはありますか?

たとえば、私はよく使用します:

if (someobject != null) {
    someobject.doCalc();
}

以下のために、このチェックNullPointerExceptionのためにsomeobject上記のコード内のオブジェクト。

受け入れられた回答が古くなっている可能性があることに注意してください。最新のアプローチについては、https://stackoverflow.com/a/2386013/12943を参照してください


120
@Shervinがnullを推奨すると、コードの理解や信頼性が低下します。
トムホーティン-タックライン

44
Elvisオペレーターが提案されましたが、Java 7にはないようです。残念な、 ?。?:と?[]は、時間を大幅に節約できます。
スコット

72
nullを使用しないことは、他のほとんどの提案よりも優れています。例外をスローし、nullを返したり許可したりしないでください。ところで、「assert」キーワードはデフォルトで無効になっているため、役に立ちません。常に有効になっている障害メカニズムを使用する
ianpojman

13
これが、現在Scalaを使用している理由の1つです。Scalaでは、すべてをnullにすることはできません。「何も」を渡したり返したりしたい場合は、引数や戻り値の型だけではなく、明示的にOption [T]を使用する必要があります。
Thekwasti

11
@thSoft確かに、ScalaのすばらしいOption型は、言語を制御したり、拒否したりするのを嫌がる言語によって傷つけられていますnull。私はこれをhackernewsで述べ、反対票を投じ、「とにかく誰もScalaでnullを使用することはない」と述べました。何だと思いますか、同僚が書いたScalaですでにnullを見つけています。はい、彼らは「それを間違っている」ので、それについて教育を受ける必要がありますが、言語の型システムはこれから私を保護するはずであり、それはそれを防ぎます:(
Andres F.

回答:


2644

これは、中級から中級の開発者がいつか直面する傾向があるかなり一般的な問題のように聞こえます。彼らは、参加している契約を知らないか、信頼していないため、nullを防御的にオーバーチェックしています。さらに、独自のコードを記述する場合、ヌルを返すことに依存して何かを示す傾向があるため、呼び出し側はヌルをチェックする必要があります。

別の言い方をすれば、ヌルチェックが行われる2つの場合があります。

  1. nullは契約に関して有効な応答です。そして

  2. 有効な応答ではない場合。

(2)簡単です。assertステートメント(アサーション)を使用するか、失敗を許可します(たとえば、 NullPointerException)。アサーションは、1.4で追加された、十分に活用されていないJava機能です。構文は次のとおりです。

assert <condition>

または

assert <condition> : <object>

ここ<condition>で、はブール式で<object>あり、toString()メソッドの出力がエラーに含まれるオブジェクトです。

assert声明は、スローErrorAssertionError条件が真でない場合)を。デフォルトでは、Javaはアサーションを無視します。オプション-eaをJVMに渡すことにより、アサーションを有効にできます。個々のクラスおよびパッケージのアサーションを有効または無効にすることができます。これは、開発およびテスト中にアサーションを使用してコードを検証し、本番環境でそれらを無効にできることを意味しますが、テストではアサーションによるパフォーマンスへの影響はほとんどありません。

この場合、アサーションを使用しなくても問題ありません。これは、コードが失敗するだけです。これは、アサーションを使用した場合に起こります。唯一の違いは、アサーションを使用すると、より意味のある方法で、場合によっては追加の情報を使用して、アサーションが発生する可能性があることです。

(1)少し難しいです。呼び出すコードを制御できない場合は、行き詰まっています。nullが有効な応答である場合は、それを確認する必要があります。

ただし、自分で制御するコードである場合(これはよくあることです)、別の話になります。応答としてnullを使用しないでください。コレクションを返すメソッドを使用すると、簡単です。ほとんどの場合、nullではなく空のコレクション(または配列)を返します。

非コレクションでは、それはより難しいかもしれません。これを例として考えてみましょう:これらのインターフェースがある場合:

public interface Action {
  void doSomething();
}

public interface Parser {
  Action findAction(String userInput);
}

ここで、Parserは生のユーザー入力を受け取り、何かを実行するためのコマンドラインインターフェイスを実装している場合に、何かを見つけます。ここで、適切なアクションがない場合はnullを返すというコントラクトを作成できます。それはあなたが話しているヌルチェックにつながります。

別の解決策は、nullを返さず、代わりにNullオブジェクトパターンを使用することです。

public class MyParser implements Parser {
  private static Action DO_NOTHING = new Action() {
    public void doSomething() { /* do nothing */ }
  };

  public Action findAction(String userInput) {
    // ...
    if ( /* we can't find any actions */ ) {
      return DO_NOTHING;
    }
  }
}

比較:

Parser parser = ParserFactory.getParser();
if (parser == null) {
  // now what?
  // this would be an example of where null isn't (or shouldn't be) a valid response
}
Action action = parser.findAction(someInput);
if (action == null) {
  // do nothing
} else {
  action.doSomething();
}

ParserFactory.getParser().findAction(someInput).doSomething();

より簡潔なコードにつながるため、これははるかに優れた設計です。

そうは言っても、おそらくfindAction()メソッドが意味のあるエラーメッセージを伴ってExceptionをスローすることは完全に適切です-特にユーザー入力に依存している場合には。説明のない単純なNullPointerExceptionで呼び出し側のメソッドが爆破するよりも、findActionメソッドが例外をスローする方がはるかに優れています。

try {
    ParserFactory.getParser().findAction(someInput).doSomething();
} catch(ActionNotFoundException anfe) {
    userConsole.err(anfe.getMessage());
}

または、何もしないのではなく、try / catchメカニズムがあまりにも醜いと思う場合は、デフォルトのアクションでユーザーにフィードバックを提供する必要があります。

public Action findAction(final String userInput) {
    /* Code to return requested Action if found */
    return new Action() {
        public void doSomething() {
            userConsole.err("Action not found: " + userInput);
        }
    }
}

631
DO_NOTHINGアクションのステートメントに同意しません。findアクションメソッドがアクションを見つけられない場合、nullを返すのが正しいことです。コードで実際には見つからないアクションを「発見」しました。これはメソッドの原則に違反しており、使用可能なアクションを見つけています。
MetroidFan2002 2008年

266
特にリストの場合、Javaではnullが多用されることに同意します。多くのAPIは、nullではなく空のリスト/配列/コレクションを返す場合に適しています。多くの場合、代わりに例外をスローする必要がある場所でnullが使用されます。パーサーが解析できない場合は、例外がスローされます。
Laplie Anderson、

92
ここでの後者の例は、IIRC、Null Objectデザインパターンです。
スティーブンエバーズ

62
@Cshah(およびMetroidFan2002)。単純に、それをコントラクトに入れれば、見つからない戻りアクションが何もしないことは明らかです。これが呼び出し元にとって重要な情報である場合は、それが見つからないアクションであることを発見する方法を提供します(つまり、結果がDO_NOTHINGオブジェクトであったかどうかを確認するメソッドを提供します)。または、アクションが通常検出される場合でも、nullを返すのではなく、その条件を具体的に示す例外をスローする必要があります。これにより、コードが改善されます。必要に応じて、ブール値を返す別のメソッドを提供して、アクションが存在するかどうかを確認します。
Kevin Brock

35
簡潔は品質の高いコードとは異なります。ごめんなさい。コードは、エラーが有利になる状況を隠します。
gshauger、2011年

635

JetBrains IntelliJ IDEAEclipseNetbeansなどのJava IDE またはfindbugsなどのツールを使用している(または使用する予定の)場合は、注釈を使用してこの問題を解決できます。

基本的に、あなたは持っ@Nullableてい@NotNullます。

次のように、メソッドとパラメータで使用できます。

@NotNull public static String helloWorld() {
    return "Hello World";
}

または

@Nullable public static String helloWorld() {
    return "Hello World";
}

2番目の例は(IntelliJ IDEAで)コンパイルされません。

helloWorld()別のコードで最初の関数を使用する場合:

public static void main(String[] args)
{
    String result = helloWorld();
    if(result != null) {
        System.out.println(result);
    }
}

これで、IntelliJ IDEAコンパイラーは、チェックが役に立たないことを通知します。これhelloWorld()は、関数がを返さないためnullです。

パラメータの使用

void someMethod(@NotNull someParameter) { }

あなたが次のようなものを書いた場合:

someMethod(null);

これはコンパイルされません。

最後の使用例 @Nullable

@Nullable iWantToDestroyEverything() { return null; }

これを行う

iWantToDestroyEverything().something();

そして、あなたはこれが起こらないことを確信することができます。:)

これは、コンパイラーが通常よりも多くのことをチェックし、契約を強化するための良い方法です。残念ながら、すべてのコンパイラでサポートされているわけではありません。

IntelliJ IDEA 10.5以降では、他の@Nullable @NotNull実装のサポートが追加されました。

ブログ投稿を参照より柔軟で構成可能な@ Nullable / @ NotNullアノテーション


120
@NotNull@Nullableおよびその他のnullnessアノテーションはJSR 305の一部です。それらを使用して、FindBugsなどのツールで潜在的な問題を検出することもできます。
Jacek S

32
@NotNull@Nullableインターフェイスがパッケージに含まれているのは不思議なことにうんざりしていますcom.sun.istack.internal。(私はcom.sunをプロプライエタリAPIの使用に関する警告に関連付けていると思います。)
Jonik

20
コードの移植性はjetbrainsで無効になります。ideレベルに縛られる前に、私は2度(四角)考えると思います。
Java Ka Baby

10
カスタムコンパイラの使用がこの問題の実行可能な解決策であるとは本当に思いません。
Shivan Dragon

64
注釈の良いところ、@NotNullおよび@Nullableソースコードは、それらを理解していないシステムで構築されているとき、彼らはうまく低下していることですしています。したがって、実際には、コードが移植可能ではないという引数は無効になる可能性があります。これらの注釈をサポートおよび理解するシステムを使用すると、より厳密なエラーチェックの利点が得られます。これらの注釈は実行時に強制されなかったため、実行中のプログラムの品質は同じです。さらに、すべてのコンパイラはカスタムです;-)
amn

321

null値が許可されていない場合

メソッドが外部から呼び出される場合は、次のようなものから始めます。

public void method(Object object) {
  if (object == null) {
    throw new IllegalArgumentException("...");
  }

その後、そのメソッドの残りの部分では、それがobjectnull ではないことがわかります。

内部メソッド(APIの一部ではない)の場合は、nullにすることはできないことを文書化してください。

例:

public String getFirst3Chars(String text) {
  return text.subString(0, 3);
}

ただし、メソッドが値を渡すだけで、次のメソッドが値を渡すなどの場合、問題が発生する可能性があります。その場合は、上記のように引数を確認する必要があります。

nullが許可されている場合

これは本当に依存します。私がしばしばこのようなことをすることがわかった場合:

if (object == null) {
  // something
} else {
  // something else
}

だから私は分岐し、2つのまったく異なることをします。データに応じて2つの異なる処理を実行する必要があるため、醜いコードスニペットはありません。たとえば、入力を処理する必要がありますか、それとも適切なデフォルト値を計算する必要がありますか?


イディオム " if (object != null && ..." を使用することは、実際にはまれです。

イディオムを通常使用する場所の例を示すと、例を示す方が簡単な場合があります。


94
IllegalArgumentExceptionをスローする意味は何ですか?NullPointerExceptionはより明確になると思います。また、自分でnullチェックを行わない場合にもスローされます。私はアサートを使用するか、まったく使用しません。
アクセル

23
null以外のすべての値が受け入れられる可能性はほとんどありません。IllegalArgumentException、OutOfRageExceptionなどが発生する可能性があります。これが意味をなすこともあります。また、値を追加しない多くの例外クラスを作成することになる場合もあります。その場合は、IllegalArgumentExceptionを使用します。null入力に対して1つの例外を設け、それ以外のすべてに対して別の例外を設けることは意味がありません。
myplacedk 2011

7
はい、私はfail-fast-principleに同意しますが、上記の例では、値は渡されませんが、メソッドが呼び出されるオブジェクトです。そのため、同様に高速に失敗し、同時にとにかくスローされる例外をスローするためだけにnullチェックを追加しても、デバッグが容易にならないようです。
アクセル

8
セキュリティホール?JDKはこのようなコードでいっぱいです。ユーザーにスタックトレースを表示させたくない場合は、それらを無効にしてください。動作が文書化されていないことを示唆する人はいません。MySQLはCで記述されており、nullポインターの逆参照は未定義の動作であり、例外をスローするようなものではありません。
fgb 2013

8
throw new IllegalArgumentException("object==null")
するThorbjörnRavnアンデルセン

238

うわー、推奨する57の異なる方法があるとき、私は別の答えを追加するのがほとんど嫌ですがNullObject pattern、この質問に興味がある一部の人々は、Java 7の表に「null-safe」を追加する提案があることを知りたいと思うかもしれません処理」 -if-not-equal-nullロジックの合理化された構文。

Alex Millerの例は次のようになります。

public String getPostcode(Person person) {  
  return person?.getAddress()?.getPostcode();  
}  

これ?.は、左識別子がnullでない場合にのみ逆参照することを意味します。それ以外の場合は、式の残りの部分をとして評価しnullます。Java PosseのメンバーであるDick WallやDevoxx有権者など、一部の人々はこの提案を本当に気に入っていますがnull、センチネル値としての使用を実際に奨励するという理由で反対もあります。


更新: Java 7のnullセーフオペレーターの公式提案Project Coinの下で提出されました構文は上の例とは少し異なりますが、同じ概念です。


更新: nullセーフオペレーターの提案は、Project Coinに組み込まれませんでした。そのため、Java 7ではこの構文は表示されません。


20
これは間違っていると思います。特定の変数が常にnull以外であることを指定する方法が必要です。
するThorbjörnRavnアンデルセン

5
更新:この提案ではJava7は作成されません。blogs.sun.com/darcy/entry/project_coin_final_fiveを参照してください。
Boris Terzic、2009

9
興味深いアイデアですが、構文の選択はばかげています。すべてのジョイントに固定された疑問符でいっぱいのコードベースが欲しくありません。
Rob

7
この演算子はGroovyに存在するので、それを使用したい人はオプションとしてそれを利用できます。
Muhd 2013

8
これは私が見た中で最も独創的なアイデアです。C構文のすべての実用的な言語に追加する必要があります。画面全体をスクロールしたり、終日「ガード句」をかわしたりするより、どこにでも「クエスチョンマークを固定」した方がいいです。
ビクター

196

未定義の値が許可されない場合:

潜在的なnull逆参照について警告するようにIDEを構成する場合があります。たとえば、Eclipseの場合は、[設定]> [Java]> [コンパイラ]> [エラー/警告/ Null分析]を参照してください。

未定義の値が許可されている場合:

未定義の値が意味をなす新しいAPIを定義する場合は、オプションパターンを使用します(関数型言語でおなじみかもしれません)。次の利点があります。

  • 入力または出力が存在するかどうかは、APIで明示的に記述されています。
  • コンパイラーは、「未定義」のケースを処理するように強制します。
  • オプションはモナドであるため、詳細なnullチェックは必要ありません。値を安全に使用するには、map / foreach / getOrElseまたは同様のコンビネーターを使用してください(例)

Java 8には組み込みOptionalクラスがあります(推奨)。以前のバージョンのために、ライブラリーの選択肢があります例えばグァバOptionalFunctionalJavaさんOption。ただし、多くの関数型パターンと同様に、Option in Java(8でも)を使用すると、かなり定型的な結果が得られます。これは、ScalaやXtendなどのより冗長でないJVM言語を使用して減らすことができます。

nullを返す可能性のあるAPIを処理する必要がある場合、Javaでは多くのことはできません。XtendとGroovyにはElvis演算子 ?:nullセーフの間接参照演算子 ?.がありますが、null参照の場合はnullが返されるため、nullの適切な処理を「延期」するだけです。


22
確かに、オプションパターンは素晴らしいです。同等のJavaがいくつか存在します。グアバには、オプションと呼ばれるこの機能の限定バージョンが含まれています。Haskellでは、このパターンはMaybeと呼ばれています。
ベンハーディ

9
オプションクラスはJava 8で利用可能になります
ピエールヘンリー

1
...そして(まだ)マップもflatMapもありません:download.java.net/jdk8/docs/api/java/util/Optional.html
thSoft

3
Optionalパターンは何も解決しません。nullの可能性がある1つのオブジェクトではなく、2つになります。
Boann 2013年

1
@Boann、注意して使用すると、NPEの問題をすべて解決できます。そうでない場合は、「使用法」の問題があると思います。
Louis F.

189

この状況でのみ-

equalsメソッドを呼び出す前に変数がnullかどうかをチェックしない(以下の文字列比較の例):

if ( foo.equals("bar") ) {
 // ...
}

NullPointerExceptionif fooが存在しない場合は、

Stringのようにs を比較すると、それを回避できます。

if ( "bar".equals(foo) ) {
 // ...
}

42
私は同意する-その状況でのみ。これを次の不必要なレベルに引き上げたプログラマに我慢できず、if(null!= myVar)...と書いて、私には醜く見え、目的を果たさない!
Alex Worden、

20
これは特定の例であり、おそらく最もよく使用される一般的な優れた実践例です<object that you know that is not null>.equals(<object that might be null>);。知っている場合は、常に実行してください。equalsコントラクトがわかっていて、それらのメソッドがnullパラメーターを処理できる場合を除いて、他のメソッドでも機能します。
Stef

9
これは、実際に理にかなっているヨーダコンディションで見た最初の例です
エリンドラモンド2013

6
何らかの理由でNullPointerExceptionsがスローされます。オブジェクトは、本来あるべき場所ではないnullであるためにスローされます。これを修正するのはプログラマの仕事であり、問​​題を隠すことではありません。
Oliver Watkins

1
Try-Catch-DoNothingは問題を隠します。これは、言語の欠けている砂糖を回避する有効な方法です。
echox 2014年

167

Java 8には、java.util.Optional間違いなくいくつかの問題を解決する新しいクラスが付属しています。少なくともコードの可読性が向上すると言えるでしょう。また、パブリックAPIの場合、APIの契約をクライアント開発者に明確にします。

彼らはそのように働きます:

指定されたタイプ(Fruit)のオプションのオブジェクトは、メソッドの戻りタイプとして作成されます。空またはFruitオブジェクトを含めることができます。

public static Optional<Fruit> find(String name, List<Fruit> fruits) {
   for (Fruit fruit : fruits) {
      if (fruit.getName().equals(name)) {
         return Optional.of(fruit);
      }
   }
   return Optional.empty();
}

Fruitfruits)のリストで特定のFruitインスタンスを検索する次のコードを見てください。

Optional<Fruit> found = find("lemon", fruits);
if (found.isPresent()) {
   Fruit fruit = found.get();
   String name = fruit.getName();
}

map()演算子を使用して、オプションのオブジェクトに対して計算を実行したり、オプションのオブジェクトから値を抽出したりできます。 orElse()欠損値のフォールバックを提供できます。

String nameOrNull = find("lemon", fruits)
    .map(f -> f.getName())
    .orElse("empty-name");

もちろん、null /空の値のチェックは依然として必要ですが、少なくとも開発者は値が空である可能性があることを意識しており、チェックを忘れるリスクは限られています。

Optional戻り値が空である可能性がある場合は常に使用して最初から作成されたAPI で、それができない場合にのみプレーンオブジェクトを返すnull(従来)場合、クライアントコードは単純なオブジェクトの戻り値のnullチェックを放棄する可能性があります...

もちろんOptional、メソッドの引数として使用することもできます。場合によっては、5または10のオーバーロードメソッドよりもオプションの引数を示すより良い方法です。

OptionalorElse、デフォルト値の使用を許可する、ラムダ式ifPresentで機能するなど、他の便利なメソッドを提供します。

この記事(この回答を書くための私の主な情報源)を読むことをお勧めします。この記事では、NullPointerException(および一般にnullポインター)問題のある(および部分的な)ソリューションOptionalがよく説明されています:Java Optional Objects


11
Googleのguavaには、Java 6以降のオプションの実装があります。
Bradley Gottfried 2013年

13
それはです非常に ifPresent(とのみオプション)を使用することはないことを強調することは重要ではない通常のヌルチェックの上に多くの価値を追加します。その中心的な価値は、map / flapMapの関数チェーンで使用できるモナドであることです。これにより、他の場所で言及されているGroovyのElvis演算子と同様の結果が得られます。ただし、この使用方法がなくても、orElse / orElseThrow構文も非常に便利です。
Cornel Masson 2014年

このブログには、オプションのWinterbe.com/posts/2015/03/15/avoid-null-checks-in-java
JohnC

4
if(optional.isPresent()){ optional.get(); }代わりに人々がこれを行う傾向がある理由optional.ifPresent(o -> { ...})
Satyendra Kumar

1
したがって、APIの契約上のヒント以外は、メソッドを無限に連鎖することを楽しむ関数型プログラマーに対応することです。
クラッシュ

125

チェックするオブジェクトの種類によっては、次のようなapache commonsのクラスの一部を使用できる場合があります。apache commons langおよびapache commonsコレクション

例:

String foo;
...
if( StringUtils.isBlank( foo ) ) {
   ///do something
}

または(確認する必要があるものに応じて):

String foo;
...
if( StringUtils.isEmpty( foo ) ) {
   ///do something
}

StringUtilsクラスは多くの1つにすぎません。コモンズには、nullセーフ操作を行う優れたクラスがかなりあります。

Apacheライブラリ(commons-lang-2.4.jar)をインクルードする場合、JAVAでnull検証を使用する方法の例を次に示します

public DOCUMENT read(String xml, ValidationEventHandler validationEventHandler) {
    Validate.notNull(validationEventHandler,"ValidationHandler not Injected");
    return read(new StringReader(xml), true, validationEventHandler);
}

また、Springを使用している場合、Springのパッケージにも同じ機能があります。library(spring-2.4.6.jar)を参照してください。

spring(org.springframework.util.Assert)からこの静的クラスを使用する方法の例

Assert.notNull(validationEventHandler,"ValidationHandler not Injected");

5
また、Apache Commonsのより一般的なバージョンを使用することもできます。これは、メソッドの開始時に、見つかったパラメーターを確認するのに非常に役立ちます。Validate.notNull(object、 "オブジェクトはnullであってはなりません"); commons.apache.org/lang/apidocs/org/apache/commons/lang/…– monojohnny 2010
1

@monojohnnyでは、ValidateはAssertステートメントを使用していますか?AssertはJVMでアクティブ化/非アクティブ化される可能性があるため、本番環境では使用しないことをお勧めします。
クラピカ

そうは思わない-検証が失敗した場合は、RuntimeExceptionをスローするだけだと思います
monojohnny

96
  • オブジェクトがnullであってはならない(またはバグである)と考える場合は、アサートを使用してください。
  • メソッドがnullパラメータを受け入れない場合は、javadocでそれを指定し、アサートを使用します。

オブジェクトがnullの可能性がある場合を処理する場合にのみ、オブジェクトをチェックする必要があります!= null ...

null / notnullパラメータを支援するためにJava7に新しい注釈を追加する提案があります:http ://tech.puredanger.com/java7/#jsr308



91

私は「失敗速く」コードのファンです。自問してみてください-パラメータがnullの場合に何か便利なことをしていますか?その場合にコードで何をすべきかについて明確な答えがない場合...つまり、そもそもそれがnullであってはならないので、それを無視してNullPointerExceptionがスローされるようにします。呼び出し側のコードは、IllegalArgumentExceptionと同様にNPEの意味を理解しますが、コードが他の予期しない不測の事態を実行しようとするよりも、NPEがスローされた場合に、開発者がデバッグして問題を理解する方が簡単です。ロジック-いずれにしても、最終的にはアプリケーションが失敗します。


2
アサーション、つまりContract.notNull(abc、 "abcはnull以外である必要があります。xyz中にロードに失敗しましたか?"); -これは、if(abc!= null){新しいRuntimeExceptionをスローする...}よりもコンパクトな方法です
ianpojman

76

Googleコレクションフレームワークは、ヌルチェックを実現するための優れたエレガントな方法を提供します。

次のようなライブラリクラスにメソッドがあります。

static <T> T checkNotNull(T e) {
   if (e == null) {
      throw new NullPointerException();
   }
   return e;
}

そして使用法は(とimport static)です:

...
void foo(int a, Person p) {
   if (checkNotNull(p).getAge() > a) {
      ...
   }
   else {
      ...
   }
}
...

またはあなたの例では:

checkNotNull(someobject).doCalc();

71
うーん、違いは何ですか?p.getAge()は、オーバーヘッドが少なく、スタックトレースがより明確な同じNPEをスローします。何が欠けていますか?
mysomic 2009年

15
IllegalArgumentException( "e == null")は、プログラマが意図した例外であることを明示しているので(メンテナが問題を実際に特定するのに十分な情報とともに)、IllegalArgumentException( "e == null")をスローすることをお勧めします。NullPointerExceptionsはJVMのために予約する必要があります。これは、これが意図的ではなかった(そして通常、特定が困難な場所で発生する)ことを明確に示すためです。
ThorbjørnRavn Andersen

6
これは現在Google Guavaの一部です。
Steven Benitez、2011

32
私には過剰なエンジニアリングのようなにおいがします。JVMにNPEをスローさせ、このジャンクでコードが乱雑にならないようにしてください。
Alex Worden

5
私はそれが好きで、ほとんどのメソッドとコンストラクターを引数の明示的なチェックで開きます。エラーがある場合、メソッドは常に最初の数行で失敗し、次のようなものを見つけることなく問題の参照を知っていますgetThing().getItsThing().getOtherThing().wowEncapsulationIsBroken().setLol("hi");
Cory Kendall

75

対称操作を定義するパラメーターを操作するメソッドがある場合があります。

a.f(b); <-> b.f(a);

bがnullになり得ないことがわかっている場合は、それを交換できます。等しい場合に最も役立ちfoo.equals("bar");ます"bar".equals(foo);


2
しかし、その場合equals(任意のメソッドである可能性がある)nullが正しく処理されると想定する必要があります。これが実際に行っていることは、責任を他の誰か(または別の方法)に渡すことです。
Supericy 2013年

4
@Supericy基本的にはそうですが、equals(または任意の方法)nullとにかくチェックする必要があります。または、そうではないことを明示的に述べます。
アンジェロフックス2013

74

Nullオブジェクトパターン(用途があります)ではなく、Nullオブジェクトがバグである状況を検討する場合があります。

例外がスローされたら、スタックトレースを調べてバグに対処します。


17
問題は、NullPointerExceptionがWHICH変数がnullであることを示しておらず、行に複数の "。"操作がある可能性があるため、通常はコンテキストが失われることです。「if(foo == null)throw new RuntimeException( "foo == null")」を使用すると、WHATが間違っていたことを明示的に示すことができ、スタックトレースを修正する必要のある人により多くの値を与えることができます。
するThorbjörnRavnアンデルセン

1
Andersenの場合-NullPointerExceptionsが例外が発生した行だけでなく変数名も示すように、Javaの例外システムで作業中の変数の名前を含めることができるようにしたいと思っています。これは、難読化されていないソフトウェアでは問題なく機能するはずです。
fwielstra '18年

まだうまく動作していませんが、これはその問題を正確に解決することを目的としています。
MatrixFrog 2011

何が問題ですか?十分なコンテキストが利用できる適切なレベルでNPEをキャッチし、コンテキスト情報をダンプして例外を再スローするだけです。Javaを使用すれば簡単です。
user1050755 2013年

3
私には、メソッド呼び出しの連鎖に対して説教する教授がいました。彼の理論では、2つのメソッドよりも長いコールチェーンには注意する必要があります。それが難しいルールかどうかはわかりませんが、NPEスタックトレースに関するほとんどの問題が確実に解消されます。
RustyTheBoyRobot

74

ヌルは「問題」ではありません。これは、完全なモデリングツールセットの不可欠な部分です。ソフトウェアは、世界の複雑さをモデル化することを目的としており、その負担はnullにあります。nullは、Javaなどでは「データなし」または「不明」を示します。したがって、これらの目的にはnullを使用することが適切です。「Nullオブジェクト」パターンは好みません。「誰が保護者を守るのか」という問題発生すると思います。
私のガールフレンドの名前は何ですかと私に尋ねたら、私にはガールフレンドがいないと言います。Java言語ではnullを返します。代わりに、意味のない例外をスローして、できない(またはできない)問題を示します

  1. 「不明な質問」の場合は「不明な答え」を入力してください。(これがビジネスの観点から正しい場合はnullセーフである)使用前にメソッド内で引数のnullを一度チェックすることで、複数の呼び出し元が呼び出しの前にそれらをチェックする必要がなくなります。

    public Photo getPhotoOfThePerson(Person person) {
        if (person == null)
            return null;
        // Grabbing some resources or intensive calculation
        // using person object anyhow.
    }

    以前は、通常のロジックフローにつながり、私の写真ライブラリから存在しないガールフレンドの写真を取得しません。

    getPhotoOfThePerson(me.getGirlfriend())

    そして、それは新しいJava APIに適合します(将来を見据えて)

    getPhotoByName(me.getGirlfriend()?.getName())

    ある人のためにDBに保存された写真を見つけないのはむしろ「通常のビジネスフロー」ですが、他のいくつかのケースでは以下のようなペアを使用していました

    public static MyEnum parseMyEnum(String value); // throws IllegalArgumentException
    public static MyEnum parseMyEnumOrNull(String value);

    そして、タイプすること<alt> + <shift> + <j>(Eclipseでjavadocを生成すること)を嫌い、パブリックAPIのために3つの追加の単語を書く必要はありません。これは、ドキュメントを読まない人以外は十分です。

    /**
     * @return photo or null
     */

    または

    /**
     * @return photo, never null
     */
  2. これはかなり理論的なケースであり、ほとんどの場合、Java nullセーフAPI(さらに10年後にリリースされる場合)を優先する必要がありますNullPointerExceptionが、のサブクラスですExceptionしたがって、これは、Throwable合理的なアプリケーションがキャッチしたい条件を示す(javadoc)の形式です!例外の一番最初の利点を使用し、エラー処理コードを「通常の」コードから分離する(Javaの作成者によると)のは、私にとって、をキャッチするのが適切NullPointerExceptionです。

    public Photo getGirlfriendPhoto() {
        try {
            return appContext.getPhotoDataSource().getPhotoByName(me.getGirlfriend().getName());
        } catch (NullPointerException e) {
            return null;
        }
    }

    質問が発生する可能性があります:

    Q. getPhotoDataSource()nullを返す場合はどうなりますか?
    A.ビジネスロジック次第です。フォトアルバムが見つからない場合、写真は表示されません。appContextが初期化されていない場合はどうなりますか?このメソッドのビジネスロジックはこれに耐えます。同じロジックをより厳密にする必要がある場合、例外をスローすることはビジネスロジックの一部であり、nullの明示的なチェックを使用する必要があります(ケース3)。より良いここに新しいJavaヌル・安全なAPIのフィットを初期化するために選択的に何を意味し、どのような意味するものではありません指定するフェイルファストプログラマのエラーの場合にあるように。

    Q.冗長なコードが実行され、不要なリソースが取得される可能性があります。
    A. getPhotoByName()データベース接続を開こうとしPreparedStatement、最後に個人名を作成してSQLパラメータとして使用しようとした場合に発生する可能性があります。未知の質問に対するアプローチは、未知の答え(ケース1)を提供します。リソースを取得する前に、メソッドはパラメータをチェックし、必要に応じて「不明な」結果を返す必要があります。

    Q.このアプローチでは、試行クロージャの開始によりパフォーマンスが低下します。
    A.ソフトウェアは、まず理解しやすく、変更しやすいものでなければなりません。この後初めて、パフォーマンスについて考えることができます。そして必要なところに!(ソース)、および他の多くの)。

    PS。このアプローチは、「通常の」コード原理とは別のエラー処理コードをどこかで使用するのが妥当であるため、使用するのが妥当です。次の例を考えてみましょう:

    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        try {
            Result1 result1 = performSomeCalculation(predicate);
            Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
            Result3 result3 = performThirdCalculation(result2.getSomeProperty());
            Result4 result4 = performLastCalculation(result3.getSomeProperty());
            return result4.getSomeProperty();
        } catch (NullPointerException e) {
            return null;
        }
    }
    
    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        SomeValue result = null;
        if (predicate != null) {
            Result1 result1 = performSomeCalculation(predicate);
            if (result1 != null && result1.getSomeProperty() != null) {
                Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
                if (result2 != null && result2.getSomeProperty() != null) {
                    Result3 result3 = performThirdCalculation(result2.getSomeProperty());
                    if (result3 != null && result3.getSomeProperty() != null) {
                        Result4 result4 = performLastCalculation(result3.getSomeProperty());
                        if (result4 != null) {
                            result = result4.getSomeProperty();
                        }
                    }
                }
            }
        }
        return result;
    }

    PPS。投票に時間がかかる(ドキュメントを読むのがそれほど速くない)場合、私は人生でnullポインタ例外(NPE)を一度もキャッチしたことがないことを伝えたいと思います。ただし、NPEはのサブクラスであるため、この可能性はJava作成者が意図的に設計したものですException。私たちがJavaの歴史で先例を持っているのThreadDeathは、Errorそれが実際にアプリケーションエラーであるからではなく、単にそれを捕捉することを意図していないからです。どのくらいのNPEフィットすることがErrorよりThreadDeath!そうではありません。

  3. ビジネスロジックが示唆する場合にのみ、「データなし」を確認します。

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person != null) {
            person.setPhoneNumber(phoneNumber);
            dataSource.updatePerson(person);
        } else {
            Person = new Person(personId);
            person.setPhoneNumber(phoneNumber);
            dataSource.insertPerson(person);
        }
    }

    そして

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person == null)
            throw new SomeReasonableUserException("What are you thinking about ???");
        person.setPhoneNumber(phoneNumber);
        dataSource.updatePerson(person);
    }

    appContextまたはdataSourceが初期化されていない場合、未処理のランタイムNullPointerExceptionは現在のスレッドを強制終了しThread.defaultUncaughtExceptionHandlerによって処理されます(お気に入りのロガーまたは他の通知メカニズムを定義して使用するため)。設定されていない場合、ThreadGroup#uncaughtExceptionはスタックトレースをシステムエラーに出力します。アプリケーションエラーログを監視し、実際にはアプリケーションエラーである未処理の例外ごとにJiraの問題を開く必要があります。プログラマーは、初期化のどこかでバグを修正する必要があります。


6
キャッチNullPointerExceptionして戻るのnullはデバッグが大変です。とにかく、後でNPEになってしまい、元々何がnullであったかを理解するのは非常に困難です。
artbristol 2013

23
評判があれば私は反対票を投じます。nullは不要であるだけでなく、型システムの穴でもあります。ツリーはリストタイプの値ではないため、ツリーをリストに割り当てるとタイプエラーになります。同じロジックで、nullの割り当ては型エラーになるはずです。nullはObject型の値ではなく、そのために役立つ型でもないためです。ヌルを発明した人でさえ、それを彼の「10億ドルの間違い」と見なしています。「T型またはNO型の値である可能性のある値」という概念はそれ自体の型であり、そのように表現する必要があります(たとえば、Maybe <T>またはOptional <T>)。
Doval 2013年

2
「Maybe <T>またはOptional <T>」の時点でも、次のようなコードを記述する必要があるif (maybeNull.hasValue()) {...}ので、何が違うのif (maybeNull != null)) {...}ですか?
Mykhaylo Adamovych 2014

1
「NullPointerExceptionをキャッチしてnullを返すのは恐ろしいことです。とにかく後でNPEになってしまい、元々何がnullだったかを理解するのは非常に困難です」。私は完全に同意します!そのような場合は、ビジネスロジックがデータをインプレースで示唆する場合は、数十の「if」ステートメントを記述するか、NPEをスローするか、新しいJavaからnullセーフな演算子を使用する必要があります。しかし、どの正確なステップがnullを与えるかについて気にしない場合があります。たとえば、データが欠落している可能性がある場合に画面に表示する直前にユーザーのいくつかの値を計算します。
Mykhaylo Adamovych 2014

3
@MykhayloAdamovych:の利点は、Maybe<T>またはOptional<T>あなたのケースではありませんTが、それはnullになることはありません場合は、nullの場合もあります。「この値 nullの可能性があります-注意して使用してください」という明示的な型があり、そのような型を一貫して使用して返す場合T、コードにプレーンな古いものが見つかるときはいつでも、それがnullになることはないと想定できます。(
もちろん

71

Java 7 java.util.Objectsには、requireNonNull()メソッドが存在する新しいユーティリティクラスがあります。これはNullPointerException、引数がnullの場合にをスローするだけですが、コードを少しクリーンアップします。例:

Objects.requireNonNull(someObject);
someObject.doCalc();

このメソッドは、コンストラクタでの割り当ての直前をチェックするのに最も役立ちます。コンストラクタを使用するたびに、次の3行のコードを節約できます。

Parent(Child child) {
   if (child == null) {
      throw new NullPointerException("child");
   }
   this.child = child;
}

なる

Parent(Child child) {
   this.child = Objects.requireNonNull(child, "child");
}

9
実際、あなたの例はコードの膨張を構成しています。NPEが2行目にスローされるため、最初の行は不必要です。;-)
user1050755

1
本当です。より良い例は、2行目がである場合doCalc(someObject)です。
Stuart Marks

依存します。あなたがdoCalc()の作成者である場合は、そのメソッドの本文にチェックを入れることをお勧めします(可能な場合)。そして、おそらくnullをチェックする必要がないsomeObject.someMethod()を呼び出すでしょう。:-)
user1050755 2013年

まあ、あなたがの作者ではなく、doCalc()nullが指定されてもすぐにNPEをスローしない場合は、nullを確認して自分でNPEをスローする必要があります。それObjects.requireNonNull()が目的です。
Stuart Marks

7
それは単なるコードの膨張ではありません。副作用を引き起こしたり、時間/スペースを使用したりする方法の途中よりも、前もってチェックする方が良い
Rob Grant

51

最終的に、この問題を完全に解決する唯一の方法は、別のプログラミング言語を使用することです。

  • Objective-Cでは、でメソッドを呼び出すのと同じことを実行できますが、nil何も起こりません。これにより、ほとんどのnullチェックが不要になりますが、エラーの診断がはるかに困難になる可能性があります。
  • ニース潜在的にヌルバージョンと非NULLバージョン:、Javaの由来言語、すべてのタイプの2つのバージョンがあります。null以外の型のメソッドのみを呼び出すことができます。nullの可能性がある型は、nullを明示的にチェックすることでnullでない型に変換できます。これにより、nullチェックが必要な場所と不要な場所を簡単に確認できます。

うわぁ...正解は正解です。正解はどこですか。Javaでは、nullは常に有効な値です。これは、Everything is a Object-Null is Everythingの当然の結果です(もちろん、ここではプリミティブを無視していますが、アイデアはわかります)。個人的には、私はニースが採用したアプローチを支持していますが、メソッドをnull許容型で呼び出すことができ、NPEをチェック例外に昇格できるようにすることもできます。これは、既存のすべてのコードが壊れるので、コンパイラスイッチを介して行う必要があります:(
CurtainDog

4
私はニースに精通していませんが、Kotlinは同じアイデアを実装しており、null許容型と非null型を言語の型システムに組み込んでいます。オプションまたはnullオブジェクトパターンよりもはるかに簡潔です。
mtsahakis

38

確かにJavaの一般的な「問題」。

まず、これについての私の考え:

NULLが有効な値ではない場合にNULLが渡されたときに何かを「食べる」ことは悪いことだと私は考えています。なんらかのエラーでメソッドを終了していない場合は、メソッドで問題が発生しておらず、真ではないことを意味します。次に、この場合はおそらくnullを返し、受信メソッドで再びnullを確認します。nullが終了することはなく、「if!= null」などになります。

つまり、私見、nullはそれ以上の実行を妨げる重大なエラーでなければなりません(つまり、nullは有効な値ではありません)。

私がこの問題を解決する方法はこれです:

まず、私はこの規則に従います:

  1. すべてのパブリックメソッド/ APIは常にその引数をnullかどうかチェックします
  2. すべてのプライベートメソッドは制御されたメソッドであるため、nullをチェックしません(上記で処理されなかった場合は、nullpointer例外で終了させて​​ください)。
  3. nullをチェックしない他の唯一のメソッドは、ユーティリティメソッドです。それらは公開されていますが、何らかの理由でそれらを呼び出すと、渡すパラメーターがわかります。これは、水を提供せずにやかんの中でお湯を沸かそうとするようなものです...

そして最後に、コードでは、publicメソッドの最初の行は次のようになります。

ValidationUtils.getNullValidator().addParam(plans, "plans").addParam(persons, "persons").validate();

addParam()はselfを返すため、確認するパラメーターをさらに追加できることに注意してください。

パラメータのいずれかがnullの場合、メソッドvalidate()はチェックをスローしますValidationException(チェックまたは非チェックは、デザイン/テイストの問題ですが、私ValidationExceptionはチェックされています)。

void validate() throws ValidationException;

たとえば、「plans」がnullの場合、メッセージには次のテキストが含まれます。

" パラメータ[プラン]で不正な引数値nullが検出されました "

ご覧のとおり、リフレクションを使用しても、渡された変数名を簡単に検出できないため(この投稿の件名ではありません...)、addParam()メソッドの2番目の値(文字列)がユーザーメッセージに必要です。

そして、はい、この行を超えるとnull値に遭遇しないことがわかっているので、それらのオブジェクトのメソッドを安全に呼び出すだけです。

このようにして、コードはクリーンで、メンテナンスが簡単で、読みやすくなっています。


3
もちろんです。エラーとクラッシュをスローするだけのアプリケーションは、いつ動作しないかは間違いないため、高品質です。エラーを最小限に抑えるアプリケーションは、正常に機能しますが、通常、気づきにくく、修正されない方法では機能しません。そして、問題に気づくと、デバッグが非常に難しくなります。
ポールジャクソン

35

その質問をすることは、エラー処理戦略に興味があるかもしれないことを指摘します。チームのアーキテクトは、エラーの処理方法を決定する必要があります。これにはいくつかの方法があります。

  1. 例外が波及することを許可-「メインループ」または他の管理ルーチンで例外をキャッチします。

    • エラー状態を確認し、適切に処理する

もちろんアスペクト指向プログラミングも見if( o == null ) handleNull()てください。バイトコードに挿入するためのすてきな方法があります。


35

を使用assertすることに加えて、以下を使用できます。

if (someobject == null) {
    // Handle null here then move on.
}

これは次のものよりわずかに優れています。

if (someobject != null) {
    .....
    .....



    .....
}

2
えっと、どうして?守備を感じないでください。Javaについてもっと学びたいと思います:)
Matthias Meid

9
@Mudu原則として、私はifステートメントの式を「否定的な」ステートメントよりも「肯定的な」ステートメントにすることを好みます。したがって、私はif (!something) { x(); } else { y(); }それをリファクタリングする傾向がありますif (something) { y(); } else { x(); }(それ!= nullがより肯定的なオプションであると主張することはできますが...)。しかし、より重要なのは、コードの重要な部分が{}s 内にラップされておらず、ほとんどのメソッドでインデントが1レベル少ないことです。それがfastcodejavaの推論だったのかどうかはわかりませんが、それは私のものです。
MatrixFrog

1
これも私がよく行う傾向です。自分の意見でコードをクリーンに保ちます。
Koray Tugay

34

nullを使用しないでください。それを許してはいけない。

私のクラスでは、ほとんどのフィールドとローカル変数にnull以外のデフォルト値があり、コードのどこにでもコントラクトステートメント(always-onアサート)を追加して、これが適用されていることを確認します(それを許可するよりも簡潔で、より表現力があるため) NPEとして起動し、行番号などを解決する必要があります)。

この方法を採用してみると、問題が解決したようです。開発プロセスのかなり早い段階で偶然に物事を把握し、弱点があることに気づくでしょう。そしてさらに重要なことに、これはさまざまなモジュールの懸念をカプセル化するのに役立ち、さまざまなモジュールが互いに「信頼」でき、散らかすことはもうありませんif = null else構文を使用したコード!

これは防御的なプログラミングであり、長期的にはよりクリーンなコードになります。厳密な基準を適用するなどして、常にデータをサニタイズします。問題が解消されます。

class C {
    private final MyType mustBeSet;
    public C(MyType mything) {
       mustBeSet=Contract.notNull(mything);
    }
   private String name = "<unknown>";
   public void setName(String s) {
      name = Contract.notNull(s);
   }
}


class Contract {
    public static <T> T notNull(T t) { if (t == null) { throw new ContractException("argument must be non-null"); return t; }
}

コントラクトは、本番環境でも常に実行されるミニユニットテストのようなものであり、物事が失敗した場合、ランダムなNPEではなく、なぜかを理解する必要があります。


なぜこれが反対投票されるのですか?私の経験では、これは他のアプローチよりもはるかに優れています。なぜそうでないのか知りたいと
思います

私は同意します、このアプローチはnullに関連する問題を防ぐのではなく、どこでもコードnullチェックをスペックル化することによってそれらを修正するのではありません。
ChrisBlom 2013

7
このアプローチの問題は、名前が設定されていない場合、値が「<unknown>」になり、設定値のように動作することです。ここで、名前が設定されていない(不明)かどうかを確認する必要があるとしましょう。特別な値 "<unknown>"に対して文字列比較を行う必要があります。
Steve Kuo

1
本当に良い点スティーブ。私がよく行うことは、その値を定数として持つことです。たとえば、public static final String UNSET = "__ unset" ... private String field = UNSET ... then private boolean isSet(){return UNSET.equals(field); }
ianpojman 2015年

私見、これは、オプション(契約)の独自の実装によるNullオブジェクトパターンの実装です。永続クラスclassではどのように動作しますか?その場合は該当しません。
Kurapika

31

グアバ、グーグルによる非常に便利なコアライブラリは、nullを回避するための素晴らしくて便利なAPIを備えています。私が見つけUsingAndAvoidingNullExplainedは非常に役立ちます。

ウィキで説明されているように:

Optional<T>null可能なT参照をnull以外の値に置き換える方法です。Optionalには、null以外のT参照(この場合、参照が「存在する」と言う)を含めるか、何も含まない(この場合、参照が「存在しない」と言う)ことができます。「ヌルを含む」とは決して言われません。

使用法:

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5

@CodyGuldnerそう、コーディ。私はより多くのコンテキストを与えるためにリンクから関連する引用を提供しました。
Murat DeryaÖzen2014

25

これは、すべてのJava開発者にとって非常に一般的な問題です。したがって、Java 8には、コードを雑然とせずにこれらの問題に対処するための公式サポートがあります。

Java 8が導入されました java.util.Optional<T>。これは、null以外の値を保持する場合と保持しない場合があるコンテナです。Java 8では、場合によっては値がnullになる可能性のあるオブジェクトをより安全に処理する方法が提供されています。HaskellScalaのアイデアから発想を得ています。

簡単に言うと、Optionalクラスには、値が存在する場合と存在しない場合を明示的に処理するメソッドが含まれています。ただし、null参照と比較した場合の利点は、Optional <T>クラスでは、値が存在しない場合について考える必要があることです。その結果、意図しないnullポインタ例外を防ぐことができます。

上記の例では、家で利用可能な複数のアプライアンスのハンドルを返すホームサービスファクトリがあります。ただし、これらのサービスは利用可能/機能しない場合があります。つまり、NullPointerExceptionが発生する可能性があります。ifサービスを使用する前にnull 条件を追加する代わりに、それをOptional <Service>にラップしましょう。

オプションへの折り返し<T>

ファクトリからサービスの参照を取得する方法を考えてみましょう。サービス参照を返す代わりに、Optionalでラップします。返されたサービスが利用可能/機能しない可能性があることをAPIユーザーに知らせ、防御的に使用します

public Optional<Service> getRefrigertorControl() {
      Service s = new  RefrigeratorService();
       //...
      return Optional.ofNullable(s);
   }

ご覧のとおりOptional.ofNullable()、参照をラップする簡単な方法を提供します。Optionalの参照を取得する別の方法があります。Optional.empty()Optional.of()。1つはnullを再調整する代わりに空のオブジェクトを返し、もう1つはnullにできないオブジェクトをラップするためのものです。

NULLチェックを回避するのにどのように役立ちますか?

参照オブジェクトをラップすると、Optionalは、NPEなしでラップされた参照のメソッドを呼び出すための多くの便利なメソッドを提供します。

Optional ref = homeServices.getRefrigertorControl();
ref.ifPresent(HomeServices::switchItOn);

Optional.ifPresentは、null以外の値の場合、参照で指定されたコンシューマーを呼び出します。それ以外の場合は、何もしません。

@FunctionalInterface
public interface Consumer<T>

単一の入力引数を受け入れ、結果を返さない操作を表します。他のほとんどの機能的インターフェースとは異なり、コンシューマーは副作用を介して動作することが期待されています。とても綺麗で分かりやすいです。上記のコード例では、HomeService.switchOn(Service)は、省略可能な保持参照がnull以外の場合に呼び出されます。

3項演算子はnull条件のチェックに頻繁に使用され、代替値またはデフォルト値を返します。オプションは、nullをチェックせずに同じ条件を処理する別の方法を提供します。Optional.orElse(defaultObj)は、Optionalにnull値がある場合にdefaultObjを返します。これをサンプルコードで使用してみましょう。

public static Optional<HomeServices> get() {
    service = Optional.of(service.orElse(new HomeServices()));
    return service;
}

現在、HomeServices.get()は同じことを行いますが、より良い方法で行われます。サービスがすでに初期化されているかどうかをチェックします。場合は同じを返すか、新しい新しいサービスを作成します。Optional <T> .orElse(T)は、デフォルト値を返すのに役立ちます。

最後に、NPEおよびnullチェックフリーコードを次に示します。

import java.util.Optional;
public class HomeServices {
    private static final int NOW = 0;
    private static Optional<HomeServices> service;

public static Optional<HomeServices> get() {
    service = Optional.of(service.orElse(new HomeServices()));
    return service;
}

public Optional<Service> getRefrigertorControl() {
    Service s = new  RefrigeratorService();
    //...
    return Optional.ofNullable(s);
}

public static void main(String[] args) {
    /* Get Home Services handle */
    Optional<HomeServices> homeServices = HomeServices.get();
    if(homeServices != null) {
        Optional<Service> refrigertorControl = homeServices.get().getRefrigertorControl();
        refrigertorControl.ifPresent(HomeServices::switchItOn);
    }
}

public static void switchItOn(Service s){
         //...
    }
}

完全な投稿は、NPEとNullチェックフリーコードです…本当に?


上記のコードにはnullチェックがあります。if(homeServices != null) {これはに変更できますhomeServices.ifPresent(h -> //action)
KrishPrabakar

23

Nat Pryceの記事が好きです。ここにリンクがあります:

記事には、私が興味深いと思うJava Maybe TypeのGitリポジトリへのリンクもありますが、それだけでチェックコードの膨張を減らすことはできないと思います。インターネットでいくつかの調査を行った後、私は!= nullコードの膨張は主に注意深い設計によって減らすことができると思います。


Michael Feathersが、あなたが言及したようなアプローチについての短い興味深いテキストを書いています: manuelp.newsblur.com/site/424
ivan.aguirre 2013

21

私は試しましたNullObjectPatternが、私にとっては必ずしも最善の方法ではありません。「アクションなし」が適切でない場合があります。

NullPointerExceptionあるランタイム例外、開発者の責任であり、十分な経験があれば、エラーの正確な場所がわかります。

今答えに:

すべての属性とそのアクセサーをできるだけプライベートにするか、クライアントに公開しないようにします。もちろん、コンストラクターで引数の値を持つことができますが、スコープを縮小することで、クライアントクラスに無効な値を渡させません。値を変更する必要がある場合は、いつでも新しいを作成できますobject。コンストラクタの値を一度だけチェックしますで、残りのメソッドでは値がnullでないことをほぼ確認できます。

もちろん、経験がこ​​の提案を理解して適用するためのより良い方法です。

バイト!


19

おそらく、Java 8以降の最良の代替手段は、Optionalクラスを使用することです。

Optional stringToUse = Optional.of("optional is there");
stringToUse.ifPresent(System.out::println);

これは、可能なnull値の長いチェーンの場合に特に便利です。例:

Optional<Integer> i = Optional.ofNullable(wsObject.getFoo())
    .map(f -> f.getBar())
    .map(b -> b.getBaz())
    .map(b -> b.getInt());

nullで例外をスローする方法の例:

Optional optionalCarNull = Optional.ofNullable(someNull);
optionalCarNull.orElseThrow(IllegalStateException::new);

Java 7では、Objects.requireNonNullnullでないかどうかを確認する必要があるときに便利なメソッドが導入されました。例:

String lowerVal = Objects.requireNonNull(someVar, "input cannot be null or empty").toLowerCase();

17

より一般的にお答えしましょうか。

私たちは通常の方法は、我々が期待していない方法でパラメータを取得するとき、この問題に直面している(悪いメソッド呼び出しは、プログラマのせいです)。たとえば、オブジェクトを取得することを期待し、代わりにnullを取得します。あなたは少なくとも1文字の文字列を取得することを期待していますが、代わりに空の文字列を取得します...

したがって、次のような違いはありません。

if(object == null){
   //you called my method badly!

}

または

if(str.length() == 0){
   //you called my method badly again!
}

どちらも、他の関数を実行する前に、有効なパラメーターを受け取ったことを確認したいと考えています。

他のいくつかの回答で述べたように、上記の問題を回避するために、契約パターンによる設計に従うことができます。http://en.wikipedia.org/wiki/Design_by_contractを参照してください

このパターンをJavaに実装するには、javax.annotation.NotNullなどのコアJavaアノテーションを使用するか、Hibernate Validatorなどのより高度なライブラリを使用できます。

単なるサンプル:

getCustomerAccounts(@NotEmpty String customerId,@Size(min = 1) String accountType)

これで、入力パラメーターをチェックする必要なく、メソッドのコア機能を安全に開発できます。これにより、予期しないパラメーターからメソッドが保護されます。

さらに一歩進んで、有効なpojoのみをアプリケーションで作成できることを確認できます。(Hibernate Validatorサイトからのサンプル)

public class Car {

   @NotNull
   private String manufacturer;

   @NotNull
   @Size(min = 2, max = 14)
   private String licensePlate;

   @Min(2)
   private int seatCount;

   // ...
}

javax定義上、「コアJava」ではありません
トーマス、

17

あらゆる状況でnullオブジェクトを使用することを示唆する回答は、無視します。このパターンは、契約を破り、問題を解決するのではなく、ますます深く埋める可能性があります。不適切に使用すると、将来のメンテナンスが必要になる定型コードの別の山が作成されることは言うまでもありません。

実際には、メソッドから返された何かがnullになる可能性があり、呼び出し側のコードがそれを決定する必要がある場合、状態を保証する以前の呼び出しが必要です。

また、ヌルオブジェクトパターンは、注意せずに使用するとメモリを大量に消費します。このため、NullObjectのインスタンスは所有者間で共有する必要があり、これらのそれぞれの一意のインスタンスではありません。

また、型がプリミティブ型表現であることを意図しているこのパターンを使用することはお勧めしません-スカラーではない数学的エンティティのように:ベクトル、行列、複素数、および状態を保持することを意図したPOD(Plain Old Data)オブジェクトJava組み込み型の形式。後者の場合、任意の結果でゲッターメソッドを呼び出すことになります。たとえば、NullPerson.getName()メソッドは何を返す必要がありますか?

ばかげた結果を避けるために、そのようなケースを検討する価値があります。


"hasBackground()"を使用したソリューションには、1つの欠点があります-スレッドセーフではありません。1つではなく2つのメソッドを呼び出す必要がある場合は、マルチスレッド環境でシーケンス全体を同期する必要があります。
pkalinow 2016

@pkalinowこのソリューションには欠点があることを指摘するためだけに、不自然な例を作成しました。コードがマルチスレッドアプリケーションで実行することを意図していない場合、欠点はありません。スレッドセーフではないコードのおそらく90%を配置することができます。ここではコードのこの側面について話しているのではなく、デザインパターンについて話している。そして、マルチスレッド化はそれ自体がトピックです。
luke1985、2016

もちろん、シングルスレッドアプリケーションでは問題ありません。時々問題になるので、私はそのコメントを与えました。
pkalinow 2016

@pkalinowこのトピックをよく検討すると、Nullオブジェクトのデザインパターンではマルチスレッドの問題を解決できないことがわかります。だからそれは無関係です。正直なところ、このパターンがうまく収まる場所を見つけたので、私の元の答えは実際には少し間違っています。
luke1985 2016

16
  1. 変数をnullに初期化しないでください。
  2. (1)が不可能な場合は、すべてのコレクションと配列を空のコレクション/配列に初期化します。

独自のコードでこれを行うと、!= nullチェックを回避できます。

ほとんどの場合、nullチェックはコレクションまたは配列のループを保護しているように見えるため、それらを空に初期化するだけで、nullチェックは必要ありません。

// Bad
ArrayList<String> lemmings;
String[] names;

void checkLemmings() {
    if (lemmings != null) for(lemming: lemmings) {
        // do something
    }
}



// Good
ArrayList<String> lemmings = new ArrayList<String>();
String[] names = {};

void checkLemmings() {
    for(lemming: lemmings) {
        // do something
    }
}

これには小さなオーバーヘッドがありますが、コードをよりクリーンにしてNullPointerExceptionsを減らすには価値があります。



3
+1これに同意します。初期化されたオブジェクトの半分を返すことはできません。Jaxbに関連するコードとBeanコードは、このためのnotiroiusです。それは悪い習慣です。すべてのコレクションを初期化する必要があり、すべてのオブジェクトは(理想的には)null参照なしで存在する必要があります。コレクションを含むオブジェクトを考えてみましょう。オブジェクトがnullでないこと、コレクションがnullではないこと、およびコレクションにnullオブジェクトが含まれていないことをチェックすることは、不合理で愚かです。
ggb667 2013

15

これは、ほとんどの開発者に発生する最も一般的なエラーです。

これを処理する方法はいくつかあります。

アプローチ1:

org.apache.commons.lang.Validate //using apache framework

notNull(オブジェクトオブジェクト、文字列メッセージ)

アプローチ2:

if(someObject!=null){ // simply checking against null
}

アプローチ3:

@isNull @Nullable  // using annotation based validation

アプローチ4:

// by writing static method and calling it across whereever we needed to check the validation

static <T> T isNull(someObject e){  
   if(e == null){
      throw new NullPointerException();
   }
   return e;
}

広告。4.あまり役に立ちません-ポインタがnullかどうかを確認するとき、おそらくそのメソッドを呼び出したいでしょう。nullでメソッドを呼び出すと、同じ動作-NullPointerExceptionが発生します。
pkalinow 2016

11
public static <T> T ifNull(T toCheck, T ifNull) {
    if (toCheck == null) {
           return ifNull;
    }
    return toCheck;
}

2
このメソッドの何が問題になっているのか、@ tltesterは、nullの場合にデフォルト値を指定したいと考えています。
Sawyer

1
Apache commons-lang:にはそのようなメソッドがありますObjectUtils.defaultIfNull()。:より一般的なものがあるObjectUtils.firstNonNull()分解戦略を実行するために使用することができ、:firstNonNull(bestChoice, secondBest, thirdBest, fallBack);
ivant
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.