Java プログラマーにとって、null は頭痛の種です。 Null Pointer Exceptions (NPE) による嫌がらせを受けることがよくあります。 Java の発明者ですら、これは大きな間違いだったと認めています。 Java が null を保持するのはなぜですか? null はしばらく前から存在しており、null が解決する問題よりも多くの問題を引き起こすことを Java の発明者は知っていたと思いますが、null は依然として Java に存在します。
Java の設計原則は物事を単純化することであり、そのためポインター、演算子のオーバーロード、多重継承の実装に時間を無駄にすることはありませんが、null はその逆です。そうですね、この質問に対する答えはよくわかりませんが、わかっていることは、null が Java 開発者やオープンソース コミュニティからどれほど批判されても、私たちは null と共存しなければならないということです。 null の存在を後悔するのではなく、null についてよく学び、null が正しく使用されるようにする必要があります。
なぜ Java で null を学ぶ必要があるのですか?なぜなら、null に注意を払わないと、Java は NullPointerException に悩まされ、痛い教訓を学ぶことになるからです。エネルギッシュなプログラミングは、チーム、顧客、ユーザーがより高く評価する芸術です。私の経験では、null ポインター例外の主な理由の 1 つは、Java の null に関する知識が不十分であることです。多くの人はすでに null に精通していますが、そうでない人にとっても、null について古くて新しいことを学ぶことができます。 Java の null に関する重要な知識をもう一度学びましょう。
Java の Null とは何ですか?
先ほども述べたように、null は Java において非常に重要な概念です。 null の本来の目的は、欠落しているユーザー、リソース、その他のものなど、欠落しているものを表すことです。しかし、その 1 年後、厄介な null ポインタ例外が Java プログラマに多くの嫌がらせを引き起こしました。この資料では、Java の null キーワードの基本的な詳細を学び、null チェックを最小限に抑えるためのいくつかのテクニックと厄介な null ポインタ例外を回避する方法を検討します。
1) まず第一に、null は Java のキーワードであり、public、static、final と同様です。大文字と小文字が区別され、null を Null または NULL として記述することはできません。コンパイラはそれらを認識せず、エラーを報告します。
Object obj = NULL; // Not Ok Object obj1 = null //Ok
他の言語を使用しているプログラマはこの問題を抱えているかもしれませんが、IDE を使用することでこの問題は簡単になりました。コードを入力すると、Eclipse や Netbeans などの IDE でこのエラーを修正できるようになりました。しかし、メモ帳、Vim、Emacs などの他のツールを使用すると、この問題は貴重な時間を無駄にすることになります。
2) すべてのプリミティブ型にデフォルト値があるのと同様に、int のデフォルト値は 0、boolean のデフォルト値は false、null は参照型のデフォルト値であり、大まかに言えば、それがデフォルト値です。すべてのオブジェクト タイプの。デフォルト値として false を持つブール変数を作成するのと同じように、Java の参照変数にはデフォルト値として null があります。これは、メンバー変数、ローカル変数、インスタンス変数、静的変数など、すべての変数に当てはまります (ただし、初期化されていないローカル変数を使用すると、コンパイラによって警告が表示されます)。この事実を証明するには、次のコードに示すように、変数を作成してその値を出力することで、この参照変数を観察できます。正しい。ここでわかるように、myObj を静的参照として定義し、main メソッドで直接使用できるようにしました。 main メソッドは静的メソッドであるため、非静的変数は使用できないことに注意してください。
3) Null はオブジェクトでも型でもありません。null を任意の型に変換することもできます。 :
private static Object myObj; public static void main(String args[]){ System.out.println("What is value of myObjc : " + myObj); }
コンパイル時および実行時に null を任意の参照型にキャストすることが可能であり、実行時に null ポインター例外がスローされないことがわかります。
4) Null を参照変数に割り当てることはできますが、int、double、float、boolean などの基本型変数に null を割り当てることはできません。これを行うと、コンパイラは次のようなエラーを報告します:
What is value of myObjc : null
ご覧のとおり、null を基本型に直接代入すると、コンパイル エラーが発生します。ただし、ラッパー クラス オブジェクトに null を割り当ててから、それぞれの基本型にオブジェクトを割り当てた場合、コンパイラはそれを報告しませんが、実行時に null ポインター例外が発生します。これは Java の自動アンボックス化が原因で発生します。これについては次の箇条書きで説明します。
5) null 値を含むラッパー クラスは、Java がボックス化を解除して基本データ型を生成するときに、null ポインター例外をスローします。一部のプログラマーは、オートボクシングによって null がそれぞれの基本型のデフォルト値 (int の場合は 0、boolean 型の場合は false など) に変換されると誤解しますが、それは正しくありません。以下に示すように:
String str = null; // null can be assigned to String Integer itr = null; // you can assign null to Integer also Double dbl = null; // null can also be assigned to Double String myStr = (String) null; // null can be type cast to String Integer myItr = (Integer) null; // it can also be type casted to Integer Double myDbl = (Double) null; // yes it's possible, no error
ただし、上記のコード スニペットを実行すると、メイン スレッドが null ポインタ例外をスローしていることがコンソールに表示されます。このようなエラーの多くは、HashMap および Integer キー値を使用するときに発生します。次のコードを実行するとエラーが表示されます。
import java.util.HashMap; import java.util.Map; /** * An example of Autoboxing and NullPointerExcpetion * * @author WINDOWS 8 */ public class Test { public static void main(String args[]) throws InterruptedException { Map numberAndCount = new HashMap<>(); int[] numbers = {3, 5, 7,9, 11, 13, 17, 19, 2, 3, 5, 33, 12, 5}; for(int i : numbers){ int count = numberAndCount.get(i); numberAndCount.put(i, count++); // NullPointerException here } } }
输出:
Exception in thread "main" java.lang.NullPointerException at Test.main(Test.java:25)
这段代码看起来非常简单并且没有错误。你所做的一切是找到一个数字在数组中出现了多少次,这是Java数组中典型的寻找重复的技术。开发者首先得到以前的数值,然后再加一,最后把值放回Map里。程序员可能会以为,调用put方法时,自动装箱会自己处理好将int装箱成Interger,但是他忘记了当一个数字没有计数值的时候,HashMap的get()方法将会返回null,而不是0,因为Integer的默认值是null而不是0。当把null值传递给一个int型变量的时候自动装箱将会返回空指针异常。设想一下,如果这段代码在一个if嵌套里,没有在QA环境下运行,但是你一旦放在生产环境里,BOOM:-)
6)如果使用了带有null值的引用类型变量,instanceof操作将会返回false:
Integer iAmNull = null; if(iAmNull instanceof Integer){ System.out.println("iAmNull is instance of Integer"); }else{ System.out.println("iAmNull is NOT an instance of Integer"); }
输出:
i
AmNull is NOT an instance of Integer
这是instanceof操作一个很重要的特性,使得对类型强制转换检查很有用
7)你可能知道不能调用非静态方法来使用一个值为null的引用类型变量。它将会抛出空指针异常,但是你可能不知道,你可以使用静态方法来使用一个值为null的引用类型变量。因为静态方法使用静态绑定,不会抛出空指针异常。下面是一个例子:
public class Testing { public static void main(String args[]){ Testing myObject = null; myObject.iAmStaticMethod(); myObject.iAmNonStaticMethod(); } private static void iAmStaticMethod(){ System.out.println("I am static method, can be called by null reference"); } private void iAmNonStaticMethod(){ System.out.println("I am NON static method, don't date to call me by null"); }
输出:
I am static method, can be called by null reference Exception in thread "main" java.lang.NullPointerException at Testing.main(Testing.java:11)
8)你可以将null传递给方法使用,这时方法可以接收任何引用类型,例如public void print(Object obj)可以这样调用print(null)。从编译角度来看这是可以的,但结果完全取决于方法。Null安全的方法,如在这个例子中的print方法,不会抛出空指针异常,只是优雅的退出。如果业务逻辑允许的话,推荐使用null安全的方法。
9)你可以使用==或者!=操作来比较null值,但是不能使用其他算法或者逻辑操作,例如小于或者大于。跟SQL不一样,在Java中null==null将返回true,如下所示:
public class Test { public static void main(String args[]) throws InterruptedException { String abc = null; String cde = null; if(abc == cde){ System.out.println("null == null is true in Java"); } if(null != null){ System.out.println("null != null is false in Java"); } // classical null check if(abc == null){ // do something } // not ok, compile time error if(abc > null){ } } }
输出:
null == null is true in Java
这是关于Java中null的全部。通过Java编程的一些经验和使用简单的技巧来避免空指针异常,你可以使你的代码变得null安全。因为null经常作为空或者未初始化的值,它是困惑的源头。对于方法而言,记录下null作为参数时方法有什么样的行为也是非常重要的。总而言之,记住,null是任何一个引用类型变量的默认值,在java中你不能使用null引用来调用任何的instance方法或者instance变量。