Javaでnullチェックを回避する方法は?

4112
Goran Martinic 2008-11-07 22:31.

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

これに代わる良い方法はありますか?

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

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

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

30 answers

2699
cletus 2008-11-08 02:06.

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

別の言い方をすれば、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を返さず、代わりにNullObjectパターンを使用することです。

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

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

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

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);
        }
    }
}
652
Luca Molteni 2010-03-06 00:31.

JetBrains IntelliJ IDEA、Eclipse、Netbeansなどの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アノテーション

330
myplacedk 2008-11-07 23:27.

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 && ...」を使用することは実際にはまれです。

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

240
erickson 2009-01-17 19:08.

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

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

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

?.手段だけデ参照左の識別子がnullでない場合は、そうでないとして表現の残りの部分を評価しますnull。JavaPosseのメンバーであるDickWallやDevoxxの有権者のように、この提案を本当に気に入っている人もいますが、実際にnullは番兵としての使用を促進するという理由で反対意見もあります。


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


更新:ヌルセーフオペレーターの提案は、プロジェクトコインにはなりませんでした。したがって、Java7ではこの構文は表示されません。

198
thSoft 2010-01-15 03:45.

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

潜在的なnull逆参照について警告するようにIDEを構成できます。Eclipseの場合、「設定」>「Java」>「コンパイラ」>「エラー/警告/ヌル分析」を参照してください。

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

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

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

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

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

194
echox 2008-11-10 02:24.

この状況でのみ-

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

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

なりますNullPointerException場合にはfoo存在しません。

あなたがStringこのようにあなたを比較するならば、あなたはそれを避けることができます:

if ( "bar".equals(foo) ) {
 // ...
}
170
Pierre Henry 2013-04-26 05:22.

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 / empty値のチェックは引き続き必要ですが、少なくとも開発者は、値が空である可能性があることを認識しており、チェックを忘れるリスクは限られています。

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

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

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

この記事(この回答を書くための私の主な情報源)を読むことをお勧めします。この記事では、NullPointerException問題のある(そして一般的にはnullポインター)とによってもたらされる(部分的な)解決策Optionalが十分に説明されています:Javaオプションオブジェクト

127
javamonkey79 2008-11-07 23:10.

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

例:

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");
98
pgras 2008-11-07 22:55.
  • オブジェクトがnullであってはならない(またはバグである)と考える場合は、assertを使用してください。
  • メソッドがnullパラメータを受け入れない場合は、javadocでそれを言い、assertを使用します。

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

null / notnullパラメータを支援するために、Java7に新しいアノテーションを追加する提案があります。 http://tech.puredanger.com/java7/#jsr308

92
Alex Worden 2011-05-24 08:18.

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

77
Jim Nelson 2008-11-07 22:50.

ヌルオブジェクトパターン(用途があります)ではなく、ヌルオブジェクトがバグである状況を検討するかもしれません。

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

77
user2427 2008-12-30 03:50.

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();
76
Johannes Schaub - litb 2008-11-07 23:04.

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

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

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

75
Mykhaylo Adamovych 2011-11-22 02:58.

ヌルは「問題」ではありません。これは、完全なモデリングツールセットの不可欠な部分です。ソフトウェアは世界の複雑さをモデル化することを目的としており、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 safe 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の問題を開く必要があります。プログラマーは初期化のどこかでバグを修正する必要があります。

71
Raedwald 2012-08-10 21:08.

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

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");
}
51
Michael Borgwardt 2009-07-30 10:52.

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

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

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

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

NULLが有効な値ではない場合にNULLが渡されたときに、何かを「食べる」のは悪いことだと思います。なんらかのエラーでメソッドを終了しない場合は、メソッドに問題がないことを意味しますが、これは正しくありません。次に、この場合はおそらくnullを返し、受信メソッドでnullを再度チェックすると、nullが終了することはなく、「if!= null」などになります。

したがって、IMHO、nullは、それ以上の実行を妨げる重大なエラーである必要があります(つまり、nullが有効な値ではない場合)。

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

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

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

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

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

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

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

void validate() throws ValidationException;

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

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

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

はい、この行を超えるとnull値が発生しなくなるため、これらのオブジェクトのメソッドを安全に呼び出すことができます。

このように、コードはクリーンで、保守が容易で、読みやすくなっています。

37
fastcodejava 2010-08-17 17:59.

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

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

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

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



    .....
}
36
xtofl 2008-11-07 23:27.

その質問をすることはあなたがエラー処理戦略に興味があるかもしれないことを指摘します。エラーを処理する方法と場所は、アーキテクチャに関する一般的な問題です。これを行うにはいくつかの方法があります。

私のお気に入り:例外が波及するのを許可します-「メインループ」または適切な責任を持つ他の関数で例外をキャッチします。エラー状態をチェックして適切に処理することは、専門的な責任と見なすことができます。

確かにアスペクト指向プログラミングも見てください-それらはif( o == null ) handleNull()あなたのバイトコードに挿入するためのきちんとした方法を持っています。

35
iangreen 2012-10-18 17:42.

nullを使用しないでください。それを許可しないでください。

私のクラスでは、ほとんどのフィールドとローカル変数にnull以外のデフォルト値があり、コードのどこにでもコントラクトステートメント(常にオンのアサーション)を追加して、これが強制されていることを確認します(これは、許可するよりも簡潔で表現力が高いためです) 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ではなく、何らかの理由で理解する必要があります。

31
Murat 2012-03-24 10:16.

Googleによる非常に便利なコアライブラリであるGuavaには、nullを回避するための便利で便利なAPIがあります。私が見つけUsingAndAvoidingNullExplainedは非常に役立ちます。

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

Optional<T>null許容T参照をnull以外の値に置き換える方法です。オプションには、null以外のT参照が含まれる場合(この場合、参照は「存在する」と言います)、または何も含まれない場合があります(この場合、参照は「存在しない」と言います)。「nullを含む」とは決して言われません。

使用法:

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5
26
Yogesh Devatraj 2015-04-27 18:16.

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

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

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

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

オプションへのラッピング<T>

工場からサービスの参照を取得する方法を考えてみましょう。サービス参照を返す代わりに、オプションでラップします。これにより、APIユーザーは、返されたサービスが利用可能/機能的である場合とそうでない場合があり、防御的に使用することができます。

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

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

では、NULLチェックを回避するのにどのように役立つのでしょうか。

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

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

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

@FunctionalInterface
public interface Consumer<T>

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

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

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

現在、HomeServices.get()は同じことを行いますが、より良い方法です。サービスがすでに初期化されているかどうかをチェックします。その後、同じものを返すか、新しい新しいサービスを作成します。オプションの<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チェックフリーコードです…本当に?

23
Mr Palo 2011-08-22 08:33.

ナット・プライスの記事が好きです。リンクは次のとおりです。

  • 多形ディスパッチによるヌルの回避
  • 「教えて、聞かないで」スタイルでヌルを回避する

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

21
OscarRyz 2008-11-14 12:08.

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

NullPointerExceptionランタイム例外です。これは、開発者の過失であり、十分な経験があれば、エラーがどこにあるかを正確に示します。

今答えに:

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

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

バイト!

19
Raghu K Nair 2016-03-23 14:03.

おそらく、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
Alireza Fattahi 2014-02-13 01:41.

もっと一般的に答えてもいいですか!

私たちは、通常の方法は、我々が期待していない方法でパラメータを取得するとき、この問題に直面している(悪いメソッド呼び出しは、プログラマのせいです)。例:オブジェクトを取得することを期待しますが、代わりに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アノテーションを使用するか、HibernateValidatorなどのより高度なライブラリを使用します。

単なるサンプル:

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

これで、入力パラメーターをチェックすることなく、メソッドのコア関数を安全に開発できます。これらは、予期しないパラメーターからメソッドを保護します。

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

public class Car {

   @NotNull
   private String manufacturer;

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

   @Min(2)
   private int seatCount;

   // ...
}
17
luke1985 2014-04-13 03:27.

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

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

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

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

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

16
Stuart Axon 2013-06-15 03:05.
  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を減らすには価値があります。

15
Sireesh Yarlagadda 2014-04-12 10:14.

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

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

アプローチ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;
}
11
tltester 2010-10-14 05:14.
public static <T> T ifNull(T toCheck, T ifNull) {
    if (toCheck == null) {
           return ifNull;
    }
    return toCheck;
}

Related questions

MORE COOL STUFF

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは、夫に会ったとき、典型的な交際のアドバイスに逆らいました。

マイケルシーンが非営利の俳優である理由

マイケルシーンが非営利の俳優である理由

マイケルシーンは非営利の俳優ですが、それは正確にはどういう意味ですか?

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。

「たどりつけば」をオンラインでストリーミングできない理由

「たどりつけば」をオンラインでストリーミングできない理由

ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

サロンからのヘアトリミングや個人的な寄付は、油流出を吸収して環境を保護するのに役立つマットとして再利用できます。

ホワイトハウスの最も記憶に残る結婚式を見てください

ホワイトハウスの最も記憶に残る結婚式を見てください

過去200年以上の間にホワイトハウスで結婚したのはほんの数人です。彼らは誰でしたか、そしてそこで結婚式を獲得するために何が必要ですか?

ジェイ・ブルースはどうやら子供を妊娠することによってメッツから離れて取引されていることを祝った

ジェイ・ブルースはどうやら子供を妊娠することによってメッツから離れて取引されていることを祝った

あなたが一時的に会っていなかったとき。シーズン11-1を開始したチームであるニューヨークメッツは、日曜日の午後にフィラデルフィアで行われた最後の11試合の9試合目を失いました。

スティーブンキングのアウトサイダーはトランプ時代のそれです

スティーブンキングのアウトサイダーはトランプ時代のそれです

スティーブン・キングのアウトサイダーは、多くの点で先祖返りの小説であり、80年代の全盛期から引き裂かれたように見える生き物の特徴であり、おそらくセル以来の彼の最もパルプのような本ですが、今日の恐怖の中で間違いなく設立された作品です。表面上は、形を変えるペニーワイズのような子供たちの殺人者を中心としており、その最も暗い脅威は、封じ込められず、神経質に平凡なものよりも幻想的で打ち負かされません。

スティーブンユニバースは、強烈な内部エピソードのペアで、それ自体のバックストーリーをさりげなく粉砕します

スティーブンユニバースは、強烈な内部エピソードのペアで、それ自体のバックストーリーをさりげなく粉砕します

スティーブンユニバースビーチシティのエピソードが実行されるたびに、いくつかのクライマックスイベントが発生し、スティーブンユニバースのより広い神話に対する理解の一部が失われます。これはあなたが期待していたことですか?今日のエピソードは両方とも、容赦なくゆっくりと、シーズンの終盤の主要な部分を設定する決定的な結論に向かって進みます。そして、ロナウドは、静かな納屋が倒れているのを発見した夜中にスティーブンを捕まえるためにやって来ます。月に。

ディズニーワールドの旅行のヒントを教えてください

ディズニーワールドの旅行のヒントを教えてください

「光が触れるものはすべて私たちの王国です。」今週のHackYour Cityでは、1つのテーマパークを取り上げます。

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、生後4か月の娘、モナコに母乳育児をしていると語った。

Come diventare Web Developer?

Come diventare Web Developer?

Vorresti diventare web developer e non sai da dove cominciare?! Qui troverai tutte le risposte necessarie, anche io non sapevo che strada intraprendere ma voglio aiutarti a non commettere i miei stessi errori. Cosa imparare? Le competenza essenziali per qualsiasi web developer sono almeno tre.

投資ノート:Bioscout AU$300万シード

投資ノート:Bioscout AU$300万シード

Bioscoutは、農家を運転席に置くという使命を負っています。Artesian(GrainInnovate)やUniseedと並んで、最新のシードラウンドでチームを支援できることをうれしく思います。問題真菌症による重大な作物の損失は、農民にとって試練であることが証明されています。

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

遠隔医療は、パンデミック後の時代では新しいものではなく、時代遅れの分野でもありません。しかし、業界を詳しく見ると、需要と供給の強力な持続可能性と、米国で絶え間ない革命となる強力な潜在的成長曲線を示しています。

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

2021年は、世界的なベンチャーキャピタル(VC)の資金調達にとって記録的な年でした。DealStreetAsiaによると、東南アジアも例外ではなく、この地域では年間で記録的な25の新しいユニコーンが採掘されました。

Language