NullPointerException
を避けるためにobject != null
を多用します。
これに代わる良い方法はありますか?
例えば:
if (someobject != null) {
someobject.doCalc();
}
オブジェクトがNullPointerException
であるかどうかがわからない場合、これはnull
を避けます。
受け入れられた答えは古くなっているかもしれないことに注意してください、より最近のアプローチについては https://stackoverflow.com/a/2386013/12943 を見てください。
私には、中級の開発者から中級の開発者までがある程度直面しがちな合理的に一般的な問題のように思えます。彼らは彼らが参加している契約を知らないか信頼しないかのどちらかです。さらに、自分自身のコードを書くとき、何かを示すためにnullを返すことに頼る傾向があり、したがって呼び出し側にnullをチェックするように要求します。
別の言い方をすれば、nullチェックが発生する2つの例があります。
契約に関してnullが有効な応答である場合。そして
有効な回答ではありません。
(2)は簡単です。 assert
ステートメント(アサーション)を使用するか、失敗を許可します( NullPointerException など)。アサーションは、1.4で追加された、あまり使用されていないJava機能です。構文は次のとおりです。
assert <condition>
または
assert <condition> : <object>
ここで<condition>
はブール式で、<object>
はtoString()
メソッドの出力がエラーに含まれるオブジェクトです。
条件が真でない場合、assert
ステートメントはError
(AssertionError
)をスローします。デフォルトでは、Javaはアサーションを無視します。オプション-ea
をJVMに渡すことでアサーションを有効にできます。個々のクラスおよびパッケージに対してアサーションを有効または無効にすることができます。これは、開発およびテスト中にアサーションを使用してコードを検証し、本番環境でそれらを無効にすることができることを意味します。ただし、私のテストではアサーションによるパフォーマンスへの影響はほとんどありません。
この場合にアサーションを使用しないことは問題ありません。コードが失敗するためです。これは、アサーションを使用した場合に起こります。唯一の違いは、アサーションではより意味のある方法で、場合によっては追加の情報で、より早く発生する可能性があるということです。それが、予期していなかった理由を突き止めるのに役立ちます。
(1)は少し難しいです。呼び出しているコードを制御できない場合は、動けなくなります。 nullが有効な応答である場合は、それを確認する必要があります。
あなたがコントロールするのがコードだとしたら(そしてこれはよくあることですが)、それは別の話です。応答としてnullを使用しないでください。コレクションを返すメソッドを使うと簡単です。ほとんどの場合、nullではなく空のコレクション(または配列)を返すようにします。
コレクション以外の場合は難しいかもしれません。例としてこれを考えてみましょう:あなたがこれらのインターフェースを持っているならば:
public interface Action {
void doSomething();
}
public interface Parser {
Action findAction(String userInput);
}
パーサーが生のユーザー入力を受け取り、何かをするためのコマンドラインインターフェースを実装している場合は、やるべきことを見つけます。適切なアクションがない場合は、nullを返すという契約を結ぶことになります。それはあなたが話しているnullチェックにつながります。
別の解決策は、nullを決して返さず、代わりに Null Objectパターン :を使用することです。
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メソッドがExceptionをスローする方がはるかに良いでしょう。
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);
}
}
}
<JetBrains IntelliJ IDE 、 Eclipse 、 Netbeans などのJava IDEA、または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 IDEA10.5以降では、他の@Nullable
@NotNull
実装のサポートを追加しました。
ブログ記事を参照してくださいより柔軟で設定可能な@ Nullable/@ NotNull注釈。
あなたのメソッドが外部から呼び出される場合は、次のようなものから始めてください。
public void method(Object object) {
if (object == null) {
throw new IllegalArgumentException("...");
}
それから、そのメソッドの残りの部分で、object
がnullではないことがわかります。
それが内部メソッドである(APIの一部ではない)場合は、それをnullにすることはできないことを文書化してください。
例:
public String getFirst3Chars(String text) {
return text.subString(0, 3);
}
しかし、あなたのメソッドが単に値を渡すだけで、次のメソッドがそれを渡すなどの場合、それは問題になるかもしれません。その場合は、上記のように引数を確認してください。
これは本当に違います。私がよくこんなことをしているのを見つけたら:
if (object == null) {
// something
} else {
// something else
}
それで、私は分岐して、2つの全く異なることをします。私は本当にデータに応じて2つの異なることをする必要があるので、醜いコードスニペットはありません。たとえば、入力に取り組むべきですか、それとも良いデフォルト値を計算するべきですか。
私が慣用句 "if (object != null && ...
"を使用することは実際には稀です。
慣用句を使用する場所の例を示した場合は、例を示したほうが簡単な場合があります。
NullObject pattern
を推奨する57の異なる方法がある場合、別の答えを追加するのはほとんど嫌いですが、この質問に興味のある人はJava 7 "null-safe handling" — 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のヌルセーフ演算子の 公式提案 が提出されました- Project Coin。 構文は上記の例とは少し異なりますが、同じ概念です。
更新:null-safeオペレーターの提案は、Project Coinに入れませんでした。したがって、Java 7でこの構文は表示されません。
Nullの間接参照の可能性について警告するようにIDEを設定することができます。例えば。 Eclipseでは、 Preferences> Java> Compiler> Errors/Warnings/Null analysis を参照してください。
未定義の値が意味を成す場合に新しいAPIを定義したい場合は 、 Option Pattern を使用してください(関数型言語ではよく知られているかもしれません)。次のような利点があります。
Java 8には組み込みの Optional
クラスがあります(推奨)。それ以前のバージョンでは、 Guava の Optional
や FunctionalJava の Option
のようにライブラリの選択肢があります。しかし、多くの関数型のパターンのように、JavaでOptionを使うと(8でも)、かなり定型的な結果が出ます。 ScalaまたはXtend.
nullを返す可能性があるAPIを処理する必要がある場合 、Javaではそれほどできません。 XtendとGroovyには、 Elvis演算子?:
と null-safe逆参照演算子?.
がありますが、null参照の場合はnullを返すので、nullの適切な処理は単に「延期」されます。
この状況だけのために -
Equalsメソッドを呼び出す前に変数がnullかどうかをチェックしません(以下の文字列比較の例)。
if ( foo.equals("bar") ) {
// ...
}
NullPointerException
が存在しない場合、foo
が返されます。
このようにString
を比較すれば、これを避けることができます。
if ( "bar".equals(foo) ) {
// ...
}
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();
}
ここで、与えられたFruitインスタンスについてFruit
fruits
)のリストを検索する以下のコードを見てください。
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
を使用してゼロから構築されたAPIで、null
にすることができない場合にのみプレーンなオブジェクトを返す(規約).
もちろんOptional
をメソッドの引数として使用することもできます。場合によっては、5または10個のオーバーロードメソッドよりもオプションの引数を指定するためのより良い方法です。
Optional
には、デフォルト値の使用を許可するorElse
や、_(ラムダ式 )と連携するifPresent
など、その他の便利なメソッドがあります。
NullPointerException
そして一般的にはnullポインタ)の問題とOptional
によってもたらされる(部分的な)解決策が説明されているこの記事(この答えを書くための私の主な情報源)を読んでください。_(Java Optional Objects)。
どの種類のオブジェクトをチェックしているかに応じて、次のようなApacheコモン内のクラスのいくつかを使用できるようになります。 Apache commons lang および Apache commons collection
例:
String foo;
...
if( StringUtils.isBlank( foo ) ) {
///do something
}
または(あなたがチェックする必要があるものによって):
String foo;
...
if( StringUtils.isEmpty( foo ) ) {
///do something
}
StringUtilsクラスは多数あるものの1つです。コモンには、安全な操作を無効にする優れたクラスがかなりあります。
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からのこの静的classfの使い方の例(org.springframework.util.Assert)
Assert.notNull(validationEventHandler,"ValidationHandler not Injected");
オブジェクトがnullである可能性がある場合を処理する場合に限り、object!= nullをチェックする必要があります。
Null/notnullパラメータを支援するためにJava7で新しいアノテーションを追加するという提案があります: http://tech.puredanger.com/Java7/#jsr308
私は "fail fast"コードのファンです。自問してください - あなたは、パラメータがnullの場合に何か役に立つことをしていますか?あなたのコードがその場合に何をすべきかについて明確な答えがない場合... I.e.最初はnullにしないでください。次に、それを無視してNullPointerExceptionをスローできるようにします。呼び出し元のコードは、IllegalArgumentExceptionと同じくらいNPEを理解しますが、NPEがスローされた場合は、コードが他の予期しない不測の事態を実行しようとするよりもデバッグしやすくなります。ロジック - これは、最終的にはとにかくアプリケーションの失敗につながります。
Googleのコレクションフレームワークは、nullチェックを達成するための優れた優れた方法を提供します。
このようなライブラリクラスにはメソッドがあります。
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();
場合によっては、対称操作を定義するパラメータを操作するメソッドがあります。
a.f(b); <-> b.f(a);
Bが決してnullになることがないことを知っていれば、単にそれを交換することができます。これはequalsに最も便利です: foo.equals("bar");
の代わりに"bar".equals(foo);
を実行してください。
Null Object Pattern(用途はあります)ではなく、nullオブジェクトがバグである状況を検討するとよいでしょう。
例外がスローされたら、スタックトレースを調べてバグを回避してください。
ヌルは「問題」ではありません。 complete モデリングツールセットの不可欠な部分です。ソフトウェアは、世界の複雑さをモデル化することを目指しており、nullはその負担を負っています。 Nullは、Javaなどの「データなし」または「不明」を示します。したがって、これらの目的にはヌルを使用することが適切です。 「Nullオブジェクト」パターンは好みません。私はそれが「 誰が保護者を守る 」問題を引き起こすと思います。
私のガールフレンドの名前を聞かれたら、ガールフレンドがいないと伝えます。 Java言語では、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
*/
これはかなり理論的なケースであり、ほとんどの場合、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)。 new Java Null-safe APIは、初期化することを暗示するものと暗示しないものを選択的に指定するのに適しています -プログラマーエラーの場合は高速。
Q.冗長コードが実行され、不要なリソースが取得される可能性があります。
A。 getPhotoByName()
がデータベース接続を開こうとし、PreparedStatement
を作成し、最後に人名をSQLパラメーターとして使用しようとすると、それが発生する可能性があります。不明な質問に対するアプローチは不明な回答を示します(ケース1)ここで動作します。リソースを取得する前に、メソッドはパラメーターを確認し、必要に応じて「不明な」結果を返す必要があります。
Q.この方法では、トライクロージャーを開くため、パフォーマンスが低下します。
A。ソフトウェアは、まず理解しやすく、修正しやすいものでなければなりません。この後のみ、必要な場合にのみパフォーマンスについて考えることができます!そして必要な場所! ( source )、および他の多く)。
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がException
のサブクラスであるため、Java作成者によって意図的に設計されたでした。 Javaの履歴には、ThreadDeath
がError
である場合の先例があります。これは、実際にはアプリケーションエラーではなく、単にキャッチすることを目的としていないためです。 Error
よりもThreadDeath
に適合するNPEの量!そうではありません。
ビジネスロジックがそれを意味する場合にのみ、「データなし」を確認します。
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の問題を開く必要があります。プログラマは、初期化のどこかでバグを修正する必要があります。
Java 7には、requireNonNull()
メソッドがある新しいJava.util.Objects
ユーティリティクラスがあります。引数がnullの場合はNullPointerException
がスローされますが、コードは少しクリーンアップされます。例:
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");
}
最終的に、この問題を完全に解決する唯一の方法は、異なるプログラミング言語を使用することです。
nil
に対してメソッドを呼び出すのと同じことができます。絶対に何も起こりません。これにより、ほとんどのnullチェックが不要になりますが、エラーを診断することがはるかに困難になります。確かにJavaの一般的な「問題」。
まず、これについての私の考え:
NULLが有効な値ではない場合にNULLが渡されたときに何かを「食べる」のは悪いことだと思います。何らかのエラーでメソッドを終了していないのであれば、メソッド内で問題が発生していないことを意味します。それならおそらくあなたはこの場合nullを返すでしょう、そして受信メソッドであなたは再びnullをチェックします、そしてそれは決して終わりません、そしてあなたは "if!= null"などで終わります。
したがって、私見、nullはそれ以上の実行を妨げる重大なエラーでなければなりません(つまり、nullは有効な値ではありません)。
私がこの問題を解決する方法はこれです:
まず、私はこの規約に従います。
そして最後に、コードでは、publicメソッドの最初の行は次のようになります。
ValidationUtils.getNullValidator().addParam(plans, "plans").addParam(persons, "persons").validate();
AddParam()はselfを返すので、チェックするパラメータを追加することができます。
いずれかのパラメータがnullの場合、メソッドvalidate()
はchecked ValidationException
をスローします(checkedまたはuncheckはデザインや好みの問題ですが、私のValidationException
はチェックされます)。
void validate() throws ValidationException;
たとえば、「plans」がnullの場合、メッセージには次のテキストが含まれます。
" パラメータ[plans]に不正な引数値nullが見つかりました "
ご覧のとおり、addParam()メソッドの2番目の値(string)はユーザーメッセージに必要です。なぜなら、リフレクションを使用しても渡された変数名を簡単に検出できないからです(とにかくこの投稿の対象ではありません)。
そしてもちろん、この行を過ぎるとnull値に遭遇することはなくなるので、それらのオブジェクトに対して安全にメソッドを呼び出すだけです。
このようにして、コードはクリーンで簡単に保守可能で読みやすいです。
その質問をすることはあなたがエラー処理戦略に興味があるかもしれないことを指摘します。あなたのチームの建築家は、エラーをどのように処理するかを決めるべきです。これを行うにはいくつかの方法があります。
例外が波及するのを許可する - 「メインループ」またはその他の管理ルーチンでそれらをキャッチします。
アスペクト指向プログラミングも見てください。if( o == null ) handleNull()
をあなたのバイトコードに挿入するためのきちんとした方法があります。
assert
を使うことに加えて、あなたは以下を使うことができます:
if (someobject == null) {
// Handle null here then move on.
}
これはもう少し良いです:
if (someobject != null) {
.....
.....
.....
}
Nullを使わないでください。許可しないでください。
私のクラスでは、ほとんどのフィールドとローカル変数はnull以外のデフォルト値を持っています。そしてこれが実行されることを確実にするためにコードの至る所にコントラクトステートメント(always-on assert)を追加します。 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ではなく、なぜか把握しなければならない理由がわかります。
Googleの非常に便利なコアライブラリであるGuavaには、nullを回避するためのNiceと便利なAPIがあります。 UsingAndAvoidingNullExplained とても役に立ちます。
Wikiで説明されているように:
Optional<T>
は、NULL可能なT参照を非null値に置き換える方法です。 Optionalは、nullでないT reference を含むことができます(その場合は、参照は "present"と言います)、または何も含んでいないこともありません(この場合、我々はreferenceが "present"と言う) "がありません")。 「nullを含む」とは言われません。
使用法:
Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5
これはすべてのJava開発者にとって非常に一般的な問題です。それで、雑然としたコードなしでこれらの問題に対処するためにJava 8で公式のサポートがあります。
Java 8はJava.util.Optional<T>
を導入しました。これは、null以外の値を保持する場合と保持しない場合があるコンテナです。 Java 8では、場合によっては値がnullになる可能性があるオブジェクトを処理するためのより安全な方法が提供されています。それは Haskell と Scala のアイデアからヒントを得たものです。
一言で言えば、Optionalクラスには、値が存在する場合と存在しない場合を明示的に処理するためのメソッドが含まれています。ただし、null参照と比較した場合の利点は、Optional <T>クラスを使用すると、値が存在しない場合のケースについて考えることが強制されることです。その結果、意図しないNULLポインタ例外を防ぐことができます。
上記の例では、家の中で利用可能な複数の電化製品にハンドルを返す家サービス工場があります。しかし、これらのサービスは利用可能か機能していないかもしれません。 NullPointerExceptionが発生する可能性があります。サービスを使用する前にnullのif
条件を追加する代わりに、それをOptional <Service>にラップしましょう。
オプション<T>へのラッピング
ファクトリからサービスの参照を取得する方法を考えましょう。サービス参照を返す代わりに、Optionalでラップします。 APIユーザーは、返されたサービスが利用可能か機能していないか、防御的に使用しているかどうかを知ることができます。
public Optional<Service> getRefrigertorControl() {
Service s = new RefrigeratorService();
//...
return Optional.ofNullable(s);
}
ご覧のとおり、Optional.ofNullable()
は参照をラップする簡単な方法を提供します。 Optionalの参照を取得するには、Optional.empty()
とOptional.of()
のいずれかの方法があります。一方はnullを返さずに空のオブジェクトを返すためのもので、もう一方はnull入力不可オブジェクトをラップするためのものです。
それでは、NULLチェックを避けるためにどの程度正確に役立つのでしょうか。
参照オブジェクトをラップすると、Optionalは、NPEなしでラップされた参照に対してメソッドを呼び出すための便利なメソッドを多数提供します。
Optional ref = homeServices.getRefrigertorControl();
ref.ifPresent(HomeServices::switchItOn);
Optional.ifPresentは、指定されたConsumerがnull以外の値であれば、参照を付けて呼び出します。そうでなければ、何もしません。
@FunctionalInterface
public interface Consumer<T>
単一の入力引数を受け入れて結果を返さない操作を表します。他のほとんどの機能的なインターフェースとは異なり、Consumerは副作用を介して動作することが期待されています。とてもきれいで理解しやすいです。上記のコード例では、Optionalの保持参照がnull以外の場合、HomeService.switchOn(Service)
が呼び出されます。
Null条件をチェックするために三項演算子を頻繁に使用し、代替値またはデフォルト値を返します。 Optionalは、nullをチェックせずに同じ条件を処理する別の方法を提供します。 Optionalの値がnullの場合、Optional.orElse(defaultObj)は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チェックフリーコードです。。
Nat Pryceの記事が好きです。これがリンクです。
この記事には、Java Maybe Type用のGitリポジトリへのリンクもありますが、これだけではチェックコードの肥大化を減らすことはできないと思います。インターネットでいくつかの調査をした後、 != null code bloatは主に慎重な設計によって減らすことができると思います。
私はNullObjectPattern
を試しましたが、私にとっては必ずしも最善の方法ではありません。 「行動なし」が適切でない場合があります。
NullPointerException
は 実行時例外 です。これは開発者の責任であり、十分な経験を積むとエラーの原因を正確に示します。
今答えに:
すべての属性とそのアクセサをできるだけ非公開にするか、クライアントに公開しないようにしてください。もちろんコンストラクタに引数の値を設定することもできますが、スコープを縮小することでクライアントクラスに無効な値を渡させないようにすることができます。値を変更する必要がある場合は、いつでも新しいobject
を作成できます。コンストラクタの値は once だけで確認し、それ以外のメソッドでは、値がnullではないことをほぼ確実に確認できます。
もちろん、経験がこの提案を理解し適用するためのより良い方法です。
バイト!
おそらく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.requireNonNull
メソッドを導入しました。例:
String lowerVal = Objects.requireNonNull(someVar, "input cannot be null or empty").toLowerCase();
あらゆる状況でnullオブジェクトを使用することを提案する回答は無視しています。このパターンは契約を破り、問題を解決するのではなく、より深く問題を埋める可能性があります。不適切に使用すると、将来のメンテナンスが必要となる定型コードが山積みになることは言うまでもありません。
実際には、メソッドから返されたものがnullになる可能性があり、呼び出し側のコードでそれを決定する必要がある場合は、状態を保証する以前の呼び出しが必要です。
また、注意してください、注意しないで使用された場合、nullオブジェクトパターンはメモリ不足になります。これのために - NullObjectのインスタンスは所有者間で共有されるべきであり、これらのそれぞれのための唯一のインスタンスではありません。
また、このパターンは、型がプリミティブ型表現、つまりスカラーではない数学的実体(ベクトル、行列、複素数、POD(Plain Old Data)オブジェクトなど)であることを意味する場合には使用しないことをお勧めしますJava組み込み型の形式で。後者の場合、あなたは任意の結果でgetterメソッドを呼び出すことになるでしょう。例えば、NullPerson.getName()メソッドは何を返しますか?
不合理な結果を避けるためにそのようなケースを検討する価値があります。
もっと一般的に答えてください。
メソッドが予期しない方法でパラメータを取得すると、 通常 この問題に直面します(悪いメソッド呼び出しはプログラマの責任です)。たとえば、オブジェクトを取得することを期待しています。代わりに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)
入力パラメータをチェックする必要なく、メソッドのコア機能を安全に開発できるようになりました。予期しないパラメータからメソッドを保護します。
さらに一歩進めて、有効なpojosだけをアプリケーションに作成できるようにします。 (Hibernate Validatorサイトからのサンプル)
public class Car {
@NotNull
private String manufacturer;
@NotNull
@Size(min = 2, max = 14)
private String licensePlate;
@Min(2)
private int seatCount;
// ...
}
あなた自身のコードでこれを行うと、避けることができます!= 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を少なくすることには価値があります。
これはほとんどの開発者にとって最も一般的なエラーです。
これを処理する方法はいくつかあります。
アプローチ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;
}
public static <T> T ifNull(T toCheck, T ifNull) {
if (toCheck == null) {
return ifNull;
}
return toCheck;
}
Java 8では、Java.utilパッケージにOptionalという新しいクラスOptionalが導入されました。
Java 8の利点オプション:
1.)ヌルチェックは必要ありません。
2。)実行時にNullPointerExceptionが発生しなくなりました。
3。)私たちはきれいできれいなAPIを開発することができます。
オプション - null以外の値を含む場合と含まない場合があるコンテナオブジェクト。値が存在する場合、isPresent()はtrueを返し、get()は値を返します。
詳細については、Oracleのドキュメントを参照してください。 - https://docs.Oracle.com/javase/8/docs/api/Java/util/Optional.html
Nullチェックを回避するために、以下のガイドラインに従います。
メンバー変数のlazy初期化をできるだけ避けてください。宣言自体の変数を初期化します。これはNullPointerExceptionsを処理します。
サイクルの初期にメンバー変数のmutabilityを決定します。 final
キーワードなどの言語構造を効果的に使用します。
メソッドの拡張が変更されないことがわかっている場合は、final
として宣言します。
データのmutationを可能な限り制限します。一部の変数はコンストラクターで作成でき、変更することはできません。 本当に必要な場合を除き、パブリックセッターメソッドを削除します。
例えば。アプリケーションの1つのクラス(A.Java
)がHashMap
のようなコレクションを維持していると仮定します。 A.Javaでpublic
getterメソッドを提供せず、B.Java
がMap
に要素を直接追加できるようにします。代わりに、要素をコレクションに追加するA.Java
でAPIを提供します。
// Avoid
a.getMap().put(key,value)
//recommended
public void addElement(Object key, Object value){
// Have null checks for both key and value here : single place
map.put(key,value);
}
そして最後に、try{} catch{} finally{}
ブロックを適切な場所で効果的に使用します。
Java 7
以降、クラスJava.util.Objects
が存在します。
しかしJava 8
以降は、Objects
クラスのObjects.isNull(var)
およびObjects.nonNull(var)
メソッドを使用してnullポインタチェックを実行できます。
例えば、
String var1 = null;
Date var2 = null;
Long var3 = null;
if(Objects.isNull(var1) && Objects.isNull(var2) && Objects.isNull(var3))
System.out.println("All Null");
else if (Objects.nonNull(var1) && Objects.nonNull(var2) && Objects.nonNull(var3))
System.out.println("All Not Null");
発言を避けるために全体として
if (object != null) {
....
}
java 7以降、Objects
メソッドを使用できます。
Objects.isNull(オブジェクト)
Objects.nonNull(オブジェクト)
Objects.requireNonNull(オブジェクト)
Objects.equals(object1、object2)
java 8以降、Optionalクラスを使用できます( 使用する場合 )
object.ifPresent(obj -> ...);
Java 8
object.ifPresentOrElse(obj -> ..., () -> ...);
Java 9
メソッド契約( JSR 305 )に頼り、 Find Bugs を使用する。あなたのコードをアノテーション@javax.annotation.Nullable
と@javax.annotation.Nonnnul
でマークしてください。前提条件もあります。
Preconditions.checkNotNull(object);
特別な場合(たとえば、文字列やコレクション)には、Apache-commons(またはGoogle guava)ユーティリティメソッドを使用できます。
public static boolean isEmpty(CharSequence cs)// Apache CollectionUtils
public static boolean isEmpty(Collection coll)// Apache StringUtils
public static boolean isEmpty(Map map)// Apache MapUtils
public static boolean isNullOrEmpty(@Nullable String string)//グアバ文字列
public static Object defaultIfNull(オブジェクトオブジェクト、オブジェクトデフォルト値)
もう一つの選択肢:
次の単純な関数は、nullチェックを隠すのに役立ちます(理由はわかりませんが、同じ common ライブラリの一部としては見つかりません)。
public static <T> boolean isNull(T argument) {
return (argument == null);
}
あなたは今書くことができます
if (!isNull(someobject)) {
someobject.doCalc();
}
iMOは!= null
を表現するためのより良い方法です。
配列またはVectorを渡す場所はどこでも、nullではなく空のものに初期化してください。 - こうすれば、たくさんのnullをチェックすることを避けることができ、すべてうまくいく:)
public class NonNullThing {
Vector vectorField = new Vector();
int[] arrayField = new int[0];
public NonNullThing() {
// etc
}
}
この場合、Guava Preconditionsが非常に便利であると思います。 NPEを理解する唯一の方法は行番号を見つけることなので、nullからnullへのポインタの例外を残すのは好きではありません。製造バージョンと開発バージョンの行番号は異なる場合があります。
Guavaの前提条件を使用して、nullパラメータを確認し、意味のある例外メッセージを1行で定義できます。
例えば、
Preconditions.checkNotNull(paramVal, "Method foo received null paramVal");
メソッド呼び出しの前にインターセプターを使用することができます。それこそが、 アスペクト指向プログラミング に焦点を当てることです。
M1(Object test)がメソッドで、M2がメソッド呼び出しの前にアスペクトを適用するメソッドであるとしましょうM2(Object test2)
。 test2 != null
がM1を呼び出す、そうでなければ別のことをします。それはあなたがアスペクトを適用したいと思うすべてのメソッドに対して機能します。インスタンスフィールドとコンストラクタにアスペクトを適用したい場合は AspectJ を使用できます。 Spring はメソッドの側面にも最適です。
Java 8では、T
を割り当てていない場合(およびnull
をチェックしない場合)またはタイプOptional<T>
をローカル変数/フィールド/メソッド引数/メソッド戻り型にnull
型を使用できます。 null
にできる場合。次に、_T ->
の処理にメソッドmap
を使用し、T -> Optional<R>
の処理にメソッドflatMap
を使用します。
class SomeService {
@Inject
private CompanyDao companyDao;
// return Optional<String>
public Optional<String> selectCeoCityByCompanyId0(int companyId) {
return companyDao.selectById(companyId)
.map(Company::getCeo)
.flatMap(Person::getHomeAddress)
.flatMap(Address::getCity);
}
// return String + default value
public String selectCeoCityByCompanyId1(int companyId) {
return companyDao.selectById(companyId)
.map(Company::getCeo)
.flatMap(Person::getHomeAddress)
.flatMap(Address::getCity)
.orElse("UNKNOWN");
}
// return String + exception
public String selectCeoCityByCompanyId2(int companyId) throws NoSuchElementException {
return companyDao.selectById(companyId)
.map(Company::getCeo)
.flatMap(Person::getHomeAddress)
.flatMap(Address::getCity)
.orElseThrow(NoSuchElementException::new);
}
}
interface CompanyDao {
// real situation: no company for such id -> use Optional<Company>
Optional<Company> selectById(int id);
}
class Company {
// company always has ceo -> use Person
Person ceo;
public Person getCeo() {return ceo;}
}
class Person {
// person always has name -> use String
String firstName;
// person can be without address -> use Optional<Address>
Optional<Address> homeAddress = Optional.empty();
public String getFirstName() {return firstName;}
public Optional<Address> getHomeAddress() {return homeAddress;}
}
class Address {
// address always contains country -> use String
String country;
// city field is optional -> use Optional<String>
Optional<String> city = Optional.empty();
String getCountry() {return country;}
Optional<String> getCity() {return city;}
}
Java 8以降を使用している場合はJava.util.Objects
のisNull(yourObject)
を探してください。
例: -
String myObject = null;
Objects.isNull(myObject); //will return true
Java 8では、オブジェクトを考慮してラップするOptionalクラスが追加されました。値が存在する場合、isPresent()はtrueを返し、get()は値を返します。
http://www.Oracle.com/technetwork/articles/Java/java8-optional-2175753.html
Checkerフレームワーク(JDK 7以降)を使用して、null値を静的にチェックすることもできます。これは多くの問題を解決するかもしれませんが、現在OpenJDK AFAIKでしか動作しない追加のツールを実行する必要があります。 https://checkerframework.org/ /
Java 8では、Java.utilパッケージに新しいクラスOptionalが導入されました。値の存在または不在を表すために使用されます。この新しいコンストラクトの主な利点は、nullチェックとNullPointerExceptionが多すぎないことです。ランタイムNullPointerExceptionsを回避し、クリーンできれいなJava APIまたはアプリケーションの開発をサポートします。コレクションや配列と同様に、最大1つの値を保持するコンテナでもあります。
以下は、フォローできる便利なリンクです。
さて、私は今、これは100万回技術的に答えられました、しかしこれはJavaプログラマーとの終わりのない議論であるので、私はこれを言わなければなりません。
申し訳ありませんが、私は上記のほとんどすべてに同意しません。 Javaでnullをテストする必要があるのは、Javaプログラマがメモリの処理方法を知らないからです。
私はこれをC++でのプログラミング経験が豊富なのでこれを言わないので言います。言い換えれば、あなたはする必要はありません。また、Javaでは、ぶら下がったポインタにぶつかると通常の例外が発生します。 C++では、この例外は通常キャッチされず、プログラムは終了します。
これをしたくないですか?それからいくつかの簡単な規則に従ってC/C++に従ってください。
それほど簡単に物事をインスタンス化しないでください。 think すべての「新しい」ことで多くの問題を抱えることになるので、これらの単純な規則に従ってください。
クラスはたった3つの方法でメモリにアクセスしなければならない - >
それはクラスメンバを "HAVE"することができ、彼らはこれらの規則に従うでしょう:
つまり、各リソースの所有者または親になる人を(Javaと同じように)し、その所有権を尊重する必要があります。オブジェクトはそれを作成したクラスによってのみ削除されます。また - >
何人かのメンバーは「USED」だが所有者でも「HAVE」でもない。これは別のクラスの "OWN"であり、コンストラクタに引数として渡されます。これらは別のクラスが所有しているので、絶対にこれを削除したり閉じたりしないでください。親だけができます。
クラス内のメソッドは、内部使用のためにローカルオブジェクトをインスタンス化することもできます。これは、クラスの外側に渡されることは決してありません。そうでない場合、それらは通常の "has"オブジェクトであるはずです。
最後に、これらすべてが機能するためには、階層形式のクラスを使用し、循環を行わないようにして統制のとれたデザインを作成する必要があります。
この設計では、そして上記の規則に従って、階層設計の子クラスが破棄されたポインタにアクセスすることは決してありません。これは、親が子の前に破棄されることを意味します。許す。
最後に、システムを起動するときには、上から下へ階層を構築し、下から上へと破棄する必要があることも忘れないでください。あなたはどこにもnullポインタを持つことは決してないでしょう、さもなければ誰かがルールに違反しています。
不要なnull-checks
を避ける方法は簡単です:
You need to know which variables can be null, and which cannot, and you need to be confident about which category a given variable fall into.
しかし、それは簡単に言えば十分ですが、それを達成することはより困難です。キーはconfident
部分にあります。変数がnullにならないことをどのようにして確認できるのでしょうか。
これに対する簡単な解決策や簡単な答えはありませんが、いくつかのポインタがあります。
きれいなコード。コードの動作を推論できる最も重要なことは、コードが理解しやすい問題で記述されていることです。変数が表すものに基づいて変数に名前を付け、メソッドの名前に応じてメソッドに名前を付け、Single responsibility principle
(S
のSOLID
: http://en.wikipedia。 org/wiki/SOLID_(object-oriented_design) 、各コードには単一の責任があり、これ以外のことは何もしないことを意味します)。コードがクリーンになったら、コードの複数の層/層にわたっても、それについて推論するのがはるかに簡単です。乱雑なコードでは、メソッドが何をするのかを理解しようとすると、そもそもメソッドを読んでいる理由を忘れてしまう可能性があります。 (ヒント:Robert C. Martinの「Clean Code」を読んでください)
null
値を返すことは避けてください。 null
値がプログラムの正常な機能を妨げている場合は、代わりにexception
をスローします(必ず適切なエラー処理を追加してください。)null
値を返すことが許容される場合たとえば、データベースからオブジェクトを取得しようとしています。これらの場合、null
値を処理するコードを記述し、耳の後ろにnull
を返す可能性のあるものがあることに注意してください。可能な限りnull
を返すメソッドの呼び出し側に近いnull
の値を返します(単に盲目的にコールチェーンに渡さないでください)。
パラメーターとして明示的なnull
値を決して渡さないでください(少なくともクラス間では)。 null
-パラメーターを渡すことが唯一のオプションである場合は、このパラメーターを持たない新しいメソッドを作成する方法があります。
入力を検証してください!アプリケーションへの「エントリポイント」を特定します。これらは、Webサービス、RESTサービス、リモートEJBクラス、コントローラーなどのすべてを実行できます。これらのエントリポイントの各メソッドについて、「このパラメーターがnullの場合、このメソッドは正しく実行されますか?」答えがいいえの場合は、Validate.notNull(someParam, "Can't function when someParam is null!");
を追加します。これは、必須パラメーターが欠落している場合、IllegalArgumentException
をスローします。エントリポイントでのこのタイプの検証の良い点は、エントリポイントから実行されるコードで、この変数がnullにならないことを簡単に想定できることです。また、これが失敗し、エントリポイントにある場合、コードの深部にNullPointerException
を取得した場合よりもデバッグがはるかに簡単になります。このような失敗は1つのことしか意味しないためです。クライアントは必要な情報をすべて送信しませんでした。ほとんどの場合、すべての入力パラメーターを検証する必要があります。多くのnull
- valuesを許可する必要がある場合、リファクタリング/追加が必要な不適切に設計されたインターフェイスの兆候である可能性がありますクライアントのニーズに対応します。
Collection
sを使用する場合、nullではなく空の値を返します!
データベースを使用する場合は、not null
- constraintsを利用してください。そうすれば、データベースから読み取った値をnullにすることはできず、チェックする必要がないことがわかります。
コードを構造化し、それに固執します。これにより、アプリケーションへのすべての入力が検証された場合など、コードの動作について推測することができ、これらの値が決してnullになることはないと想定できます。
まだ実行していない場合は、コードの自動テストを作成します。テストを書くことで、コードについて推論することができ、コードが意図したとおりに動作することを確信できるようになります。また、自動化されたテストは、このコードが以前のように機能していないことを即座に通知することで、リファクタリング中の失敗を防ぎます。
もちろん、nullチェックを行う必要がありますが、最小限に抑えることができます(つまり、knowがnull- nullチェックに関しては、実際には三項演算子を使用することを好みます(ただし、ネストを開始すると、それらは非常に乱雑になります)。
public String nullSafeToString(final Object o) {
return o != null ? o.toString() : "null";
}
まず第一に、私たちは本当にすべてのnull条件を削除することはできません。 @NotNull
と@Nullable
アノテーション( すでに述べたように )を使ってそれらを減らすことができます。しかし、これは何らかのフレームワークによって裏付けられる必要があります。これが OVal が助けになるところです。
基本的な考え方は、オブジェクト/パラメータ/コンストラクタは常に前提条件を満たす必要があるということです。 Nullable
、NotNull
、OValのように、起動時にオブジェクトが一貫した状態になるように注意を払う必要があります。
OValは、前提条件を検証するためにAspectJを内部的に使用していると思います。
@Guarded
public class BusinessObject
{
public BusinessObject(@NotNull String name)
{
this.name = name;
}
...
}
例えば、
// Throws a ConstraintsViolatedException because parameter name is null
BusinessObject bo = new BusinessObject(null);
この問題には、Apacheライブラリ(Apache Commons)を使用しています。
ObjectUtils.equals(object, null)
または
CollectionUtils.isEmpty(myCollection);
または
StringUtils.isEmpty("string");
実際には、必要性を最小限に抑えるためにコレクションの初期デフォルト値または空のセットを提供するという以前の回答が好きです。
これらは、NullPointerExceptionを発生させたり、空のコレクションを使用したりするのを防ぐための単純な使用法です。これはnullオブジェクトをどうするかについての質問には答えませんが、これらはオブジェクトまたはコレクションの基本的な検証のためのいくつかのチェックを提供します。
お役に立てれば。
私はこれが好きです
public void simpleFunc(SomeObject someObject){
someObject = someObject != null ? someObject : new SomeObject(null);
someObject.doSomething();
}
もちろん、私の例ではSomeObjectは優雅にnullパラメータを扱います。例えば、そのようなイベントをログに記録し、それ以上何もしない。
Java 8では、以下のようにサプライヤをヘルパーメソッドに渡すことができます。
if(CommonUtil.resolve(()-> a.b().c()).isPresent()) {
}
下のようにボイラープレートコードを上に置き換えます。
if(a!=null && a.b()!=null && a.b().c()!=null) {
}
//CommonUtil.Java
public static <T> Optional<T> resolve(Supplier<T> resolver) {
try {
T result = resolver.get();
return Optional.ofNullable(result);
} catch (NullPointerException var2) {
return Optional.empty();
}
}
Java 8のラムダで、ほとんどきれいな方法で入れ子になったnullチェックを扱うutilメソッドを定義することは可能です。
void example() {
Entry entry = new Entry();
// This is the same as H-MANs solution
Person person = getNullsafe(entry, e -> e.getPerson());
// Get object in several steps
String givenName = getNullsafe(entry, e -> e.getPerson(), p -> p.getName(), n -> n.getGivenName());
// Call void methods
doNullsafe(entry, e -> e.getPerson(), p -> p.getName(), n -> n.nameIt());
}
/** Return result of call to f1 with o1 if it is non-null, otherwise return null. */
public static <R, T1> R getNullsafe(T1 o1, Function<T1, R> f1) {
if (o1 != null) return f1.apply(o1);
return null;
}
public static <R, T0, T1> R getNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, R> f2) {
return getNullsafe(getNullsafe(o0, f1), f2);
}
public static <R, T0, T1, T2> R getNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, T2> f2, Function<T2, R> f3) {
return getNullsafe(getNullsafe(o0, f1, f2), f3);
}
/** Call consumer f1 with o1 if it is non-null, otherwise do nothing. */
public static <T1> void doNullsafe(T1 o1, Consumer<T1> f1) {
if (o1 != null) f1.accept(o1);
}
public static <T0, T1> void doNullsafe(T0 o0, Function<T0, T1> f1, Consumer<T1> f2) {
doNullsafe(getNullsafe(o0, f1), f2);
}
public static <T0, T1, T2> void doNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, T2> f2, Consumer<T2> f3) {
doNullsafe(getNullsafe(o0, f1, f2), f3);
}
class Entry {
Person getPerson() { return null; }
}
class Person {
Name getName() { return null; }
}
class Name {
void nameIt() {}
String getGivenName() { return null; }
}
(この回答は最初に投稿された here です。)
Kotlin nullの安全性を持つは優雅な代替手段ですが、それはより大きな変更を意味します。
ユーティリティクラスの場合は、パラメータがnullではないことを確認できます。
他のすべての場合では、する必要はないかもしれません。カプセル化をできるだけ使用することで、nullをチェックしたくないと思う場所を減らすことができます。
JUnitのようなフレームワークを使ってあなたのクラスとユニットテストを結びつけることができます。
これが単体テストを使用する(多くの)理由の1つです。
この問題の解決策として、ヌルオブジェクトパターンを使用できます。そのためには、someObjectのクラスを修正する必要があります。
public abstract class SomeObject {
public abstract boolean isNil();
}
public class NullObject extends SomeObject {
@Override
public boolean isNil() {
return true;
}
}
public class RealObject extends SomeObject {
@Override
public boolean isNil() {
return false;
}
}
今チェックするのではなく、
if (someobject != null) {
someobject.doCalc();
}
使用できます、
if (!someObject.isNil()) {
someobject.doCalc();
}
参照: https://www.tutorialspoint.com/design_pattern/null_object_pattern.htm
あなたが持っている一つのオプション
メソッドに checker framework の@RequiresNonNullを使用します。例えば、そのようにアノテートされたメソッドをnull引数で呼び出すとこれが得られます。コードが実行される前であっても、コンパイル中は失敗します。実行時にはNullPointerExceptionになるので
@RequiresNonNull(value = { "#1" })
static void check( Boolean x) {
if (x) System.out.println("true");
else System.out.println("false");
}
public static void main(String[] args) {
check(null);
}
取得
[ERROR] found : null
[ERROR] required: @Initialized @NonNull Boolean
[ERROR] -> [Help 1]
Use Java 8のOptional、Guava Annotations、Null Object patternなど、他の方法もあります。
!= nullチェックに代わるもう1つの方法は(デザイン的にそれを取り除けない場合):
Optional.ofNullable(someobject).ifPresent(someobject -> someobject.doCalc());
または
Optional.ofNullable(someobject).ifPresent(SomeClass::doCalc);
SomeClassはsomeobjectの型です。
ただし、doCalc()から戻り値を取得することはできません。したがって、voidメソッドにのみ役立ちます。
機能的なアプローチは、反復的なnullチェックをラップし、以下のサンプルのように匿名コードを実行するのに役立ちます。
BiConsumer<Object, Consumer<Object>> consumeIfPresent = (s,f) ->{
if(s!=null) {
f.accept(s);
}
};
consumeIfPresent.accept(null, (s)-> System.out.println(s) );
consumeIfPresent.accept("test", (s)-> System.out.println(s));
BiFunction<Object, Function<Object,Object>,Object> executeIfPresent = (a,b) ->{
if(a!=null) {
return b.apply(a);
}
return null;
};
executeIfPresent.apply(null, (s)-> {System.out.println(s);return s;} );
executeIfPresent.apply("test", (s)-> {System.out.println(s);return s;} );