Java学习笔记之深入理解关键字null

关键字null

跟publicstaticfinal一样,null也是java的关键字(更多关键字可以参考Java学习笔记之基本语法)。不能将null写成NullNULL,编译器将会报错。

1
2
3
Object obj = NULL;  // Not Ok
Object obj1 = Null; // Not Ok
Object obj2 = null; // Ok

null作为默认值

null是任何引用类型的默认值,但不能作为基本类型变量的默认值。如int的默认值为0,boolean的默认值为false(更多信息可参考Java学习笔记之基本数据类型)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Test {
static int i; // 基本类型变量int,默认值为0
static boolean j; // 基本类型变量boolean,默认值为false
static Object o; // 引用类型变量,默认值为null
static Test test; // 引用类型变量,默认值为null
public static void main(String[] args) {
System.out.println(i);
System.out.println(j);
System.out.println(o);
System.out.println(test);
}
}
/** output
0
false
null
null
*/

null能转换成任何类型

null既不是对象也不是一种类型,它仅是一种特殊的值,你可以将其赋予任何引用类型。

1
2
3
4
5
6
7
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

空指针异常(NPE)

  1. 任何含有null值的包装类在Java拆箱生成基本数据类型时候都会抛出一个空指针异常
    null是不能直接赋值给基本类型的,如果这样做,则会出现编译错误;而如果将null赋值给包装类object,然后将object赋给各自的基本类型,编译器不会报,但将会在运行时期遇到空指针异常。
    这是由于java中的自动拆箱导致的,因为自动拆箱不会将null转换成各自基本类型的默认值。

    1
    2
    3
    int i = null;       // type mismatch : cannot convert from null to int
    Integer itr = null; // this is ok
    int j = itr; // this is also ok, but NullPointerException at runtime
  2. 从已知的String对象中调用equals()和equalsIgnoreCase()方法,而非未知对象
    由于equals()方法是对称的,调用a.equals(b)和调用b.equals(a)是完全相同的,导致一些程序员忽略了a,b为空时的情况。如果调用者是空指针,这种调用可能导致一个空指针异常

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Object unknownObject = null;

    //错误方式 – 可能导致 NullPointerException
    if(unknownObject.equals("knownObject")){
    System.err.println("This may result in NullPointerException if unknownObject is null");
    }

    //正确方式 - 即便 unknownObject是null也能避免NullPointerException
    if("knownObject".equals(unknownObject)){
    System.err.println("better coding avoided NullPointerException");
    }
  3. 当valueOf()和toString()返回相同的结果时,宁愿使用前者
    由于调用null对象的toString()会抛出空指针异常,而传递一个nullvalueOf()将会返回“null”,尤其是在那些包装类,像IntegerFloatDoubleBigDecimal

    1
    2
    3
    static Integer it;
    System.out.println(String.valueOf(it)); //不会抛出空指针异常
    System.out.println(it.toString()); //抛出 "Exception in thread "main" java.lang.NullPointerException"

比较null值

除了可以使用==或者!=操作来比较null值,不能使用其他的算法或逻辑进行比较。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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){

}
}
}
/**output
null == null is true in Java
*/

空串与null串

空串””是长度为0的字符串。
可以调用以下代码进行检查一个字符串是否为空:

1
if(str.length() == 0)


1
if(str.equals(""))

空串是一个java对象,有自己的串长度(0)和内容(空)。
null串表示一个特殊的String变量,它表示目前没有任何对象与该变量关联。
可以调用以下代码进行检查一个字符串是否为null:

1
if(str == null)

如果将一个方法应用于一个值为null的对象上,就会产生运行错误,如

1
2
Integer ite = null;
String str = ite.toString(); // 空指针异常