9 Things about null in Java

Java and null are uniquely bonded. There is hardly a Java programmer, who is not troubled by null pointer exception, it is the most infamous fact about. Even inventor of null concept has called it his billion dollar mistake, then why Java kept it? Null was there from long time and I believe Java designer knows that null creates more problem than it solves, but still they went with it. It surprise me even more because Java's design philosophy was to simplify things, that's why they didn't bothered with pointers, operator overloading and multiple inheritance of implementation, they why null. Well I really don't know the answer of that question, what I know is that, doesn't matter how much null is criticized by Java developers and open source community, we have to live with that. Instead of ruing about null it's better to learn more about it and make sure we use it correct. Why you should learn about null in Java? because If you don't pay attention to null, Java will make sure that you will suffer from dreaded java.lang.NullPointerException and you will learn your lesson hard way. Robust programming is an art and your team, customer and user will appreciate that. In my experience, one of the main reasons of NullPointerException are not enough knowledge about null in Java. Many of you already familiar with null but for those, who are not, can learn some old and new things about null keyword. Let's revisit or learn some important things about null in Java.


 

What is Null in Java

As I said, null is very very important concept in Java. It was originally invented to denote absence of something e.g. absence of user, a resource or anything, but over the year it has troubled Java programmer a lot with nasty null pointer exception. In this tutorial, we will learn basic facts about null keyword in Java and explore some techniques to minimize null checks and how to avoid nasty null pointer exceptions.
 

 


1) First thing, first,  null is a keyword in Java, much like public, static or final. It's case sensitive, you cannot write null as Null or NULL, compiler will not recognize them and give error.(case-sensitive)

 
Object obj = NULL; // Not Ok Object obj1 = null //Ok


Programmer's which are coming from other language have this problem, but use of modern day IDE's has made it insignificant. Now days, IDE like Eclipse or Netbeans can correct this mistake, while you type code, but in the era of notepad, Vim and Emacs, this was a common issue which could easily eat your precious time.


2) Just like every primitive has default value e.g. int has 0, boolean has false, null is the default value of any reference type, loosely spoken to all object as well. Just like if you create a boolean variable, it got default value as false, any reference variable in Java has default value null. This is true for all kind of variables e.g. member variable or local variable, instance variable or static variable, except that compiler will warn you if you use a local variable without initializing them. In order to verify this fact, you can see value of reference variable by creating a variable and them printing it's value, as shown in following code snippet :
 

private static Object myObj;
public static void main(String args[]){
    System.out.println("What is value of myObjc : " + myObj);
} 

What is value of myObjc : null


This is true for both static and non-static object, as you can see here that I made myObj a static reference so that I can use it directly inside main method, which is static method and doesn't allow non-static variable inside.


3) Unlike common misconception, null is not Object or neither a type. It's just a special value, which can be assigned to any reference type and you can type cast null to any type, as shown below :
 

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


You can see type casting null to any reference type is fine at both compile time and runtime, unlike many of you might have thought, it will also not throw NullPointerException at runtime.


4) null can only be assigned to reference type, you cannot assign null to primitive variables e.g. int, double, float or boolean. Compiler will complain if you do so, as shown below.
 

int i = null; // type mismatch : cannot convert from null to int
short s = null; //  type mismatch : cannot convert from null to short
byte b = null: // type mismatch : cannot convert from null to byte
double d = null; //type mismatch : cannot convert from null to double
        
Integer itr = null; // this is ok
int j = itr; // this is also ok, but NullPointerException at runtime


As you can see, when you directly assign null to primitive error it's compile time error, but if you assign null to a wrapper class object and then assign that object to respective primitive type, compiler doesn't complain, but you would be greeted by null pointer exception at runtime. This happens because of autoboxing in Java, and we will see it in next point.


5) Any wrapper class with value null will throw java.lang.NullPointerException when Java unbox them into primitive values. Some programmer makes wrong assumption that, auto boxing will take care of converting null into default values for respective primitive type e.g. 0 for int, false for boolean etc, but that's not true, as seen below.
 

Integer iAmNull = null;
int i = iAmNull; // Remember - No Compilation Error


but when you run above code snippet you will see Exception in thread "main" java.lang.NullPointerException  in your console. This happens a lot while working with HashMap and Integer key values. Code like shown below will break as soon as you run.
 

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
      }       
    }

}

Output:
Exception in thread "main" java.lang.NullPointerException
 at Test.main(Test.java:25)


This code looks very simple and innocuous. All you are doing is finding how many times a number has appeared in a array, classic technique to find duplicates in Java array. Developer is getting the previous count, increasing it by one and putting it back into Map. He might have thought that auto-boxing will take care of converting Integer to int , as it doing while calling put method, but he forget that when there is no count exist for a number, get() method of HashMap will return null, not zero because default value of Integer is null not 0, and auto boxing will throw null pointer exception while trying to convert it into an int variable. Imagine if this code is inside an if loop and doesn't run in QA environment but as soon as you put into production, BOOM :-)


6)instanceof operator will return false if used against any reference variable with null value or null literal itself, e.g.
 

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");
}

Output : iAmNull is NOT an instance of Integer


This is an important property of instanceof operation which makes it useful for type casting checks.


7) You may know that you cannot call a non-static method on a reference variable with null value, it will throw NullPointerException, but you might not know that, you can call static method with reference variables with null values. Since static methods are bonded using static binding, they won't throw NPE. Here is an example :             
 

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");
   }
 
}

Output:
I am static method, can be called by null reference
Exception in thread "main" java.lang.NullPointerException
               at Testing.main(Testing.java:11)



8) You can pass null to methods, which accepts any reference type e.g. public void print(Object obj) can be called as print(null). This is Ok from compiler's point of view, but behavior is entirely depends upon method. Null safe method, doesn't throw NullPointerException in such case, they just exit gracefully. It is recommended to write null safe method if business logic allows.

9) You can compare null value using ==  (equal to ) operator and !=  (not equal to) operator, but cannot use it with other arithmetic or logical operator e.g. less than or greater than. Unlike in SQL, in Java null == null will return true, as shown below :
 

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


That's all about null in Java. By some experience in Java coding and by using simple tricks to avoid NullPointerExcpetion, you can make your code null safe. Since null can be treated as empty or uninitialized value it's often source of confusion, that's why it's more important to document behavior of a method for null input. Always remember, null is default value of any reference variable and you cannot call any instance method, or access an instance variable using null reference in Java.

Read more: http://javarevisited.blogspot.com/2014/12/9-things-about-null-in-java.html#ixzz4p828sewo

 

对于Java程序员来说,null是令人头痛的东西。时常会受到空指针异常(NPE)的骚扰。连Java的发明者都承认这是他的一项巨大失误。Java为什么要保留null呢?null出现有一段时间了,并且我认为Java发明者知道null与它解决的问题相比带来了更多的麻烦,但是null仍然陪伴着Java。

我越发感到惊奇,因为java的设计原理是为了简化事情,那就是为什么没有浪费时间在指针、操作符重载、多继承实现的原因,null却与此正好相反。好吧,我真的不知道这个问题的答案,我知道的是不管null被Java开发者和开源社区如何批评,我们必须与null共同存在。与其为null的存在感到后悔,我们倒不如更好的学习null,确保正确使用null。

为什么在Java中需要学习null?因为如果你对null不注意,Java将使你遭受空指针异常的痛苦,并且你也会得到一个沉痛的教训。精力充沛的编程是一门艺术,你的团队、客户和用户将会更加欣赏你。以我的经验来看,导致空指针异常的一个最主要的原因是对Java中null的知识还不够。你们当中的很多已经对null很熟悉了,但是对那些不是很熟悉的来说,可以学到一些关于null老的和新的知识。让我们一起重新学习Java中null的一些重要知识吧。

Java中的Null是什么?

正如我说过的那样,null是Java中一个很重要的概念。null设计初衷是为了表示一些缺失的东西,例如缺失的用户、资源或其他东西。但是,一年后,令人头疼的空指针异常给Java程序员带来不少的骚扰。在这份材料中,我们将学习到Java中null关键字的基本细节,并且探索一些技术来尽可能的减少null的检查以及如何避免恶心的空指针异常。

1)首先,null是Java中的关键字,像public、static、final。它是大小写敏感的,你不能将null写成Null或NULL,编译器将不能识别它们然后报错。

Object obj = NULL; // Not Ok
Object obj1 = null  //Ok

使用其他语言的程序员可能会有这个问题,但是现在IDE的使用已经使得这个问题变得微不足道。现在,当你敲代码的时候,IDE像Eclipse、Netbeans可以纠正这个错误。但是使用其他工具像notepad、Vim、Emacs,这个问题却会浪费你宝贵时间的。

2)就像每种原始类型都有默认值一样,如int默认值为0,boolean的默认值为false,null是任何引用类型的默认值,不严格的说是所有object类型的默认值。就像你创建了一个布尔类型的变量,它将false作为自己的默认值,Java中的任何引用变量都将null作为默认值。这对所有变量都是适用的,如成员变量、局部变量、实例变量、静态变量(但当你使用一个没有初始化的局部变量,编译器会警告你)。为了证明这个事实,你可以通过创建一个变量然后打印它的值来观察这个引用变量,如下图代码所示:

private static Object myObj;
public static void main(String args[]){
    System.out.println("What is value of myObjc : " + myObj);
}
What is value of myObjc : null

这对静态和非静态的object来说都是正确的。就像你在这里看到的这样,我将myObj定义为静态引用,所以我可以在主方法里直接使用它。注意主方法是静态方法,不可使用非静态变量。

3)我们要澄清一些误解,null既不是对象也不是一种类型,它仅是一种特殊的值,你可以将其赋予任何引用类型,你也可以将null转化成任何类型,来看下面的代码:

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强制转换成任何引用类型都是可行的,在运行时期都不会抛出空指针异常。

4)null可以赋值给引用变量,你不能将null赋给基本类型变量,例如int、double、float、boolean。如果你那样做了,编译器将会报错,如下所示:

int i = null; // type mismatch : cannot convert from null to int
short s = null; //  type mismatch : cannot convert from null to short
byte b = null: // type mismatch : cannot convert from null to byte
double d = null; //type mismatch : cannot convert from null to double

Integer itr = null; // this is ok
int j = itr; // this is also ok, but NullPointerException at runtime

正如你看到的那样,当你直接将null赋值给基本类型,会出现编译错误。但是如果将null赋值给包装类object,然后将object赋给各自的基本类型,编译器不会报,但是你将会在运行时期遇到空指针异常。这是Java中的自动拆箱导致的,我们将在下一个要点看到它。

5) 任何含有null值的包装类在Java拆箱生成基本数据类型时候都会抛出一个空指针异常。一些程序员犯这样的错误,他们认为自动装箱会将null转换成各自基本类型的默认值,例如对于int转换成0,布尔类型转换成false,但是那是不正确的,如下面所示:

Integer iAmNull = null;
int i = iAmNull; // Remember - No Compilation Error

但是当你运行上面的代码片段的时候,你会在控制台上看到主线程抛出空指针异常。在使用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变量。

原文链接: javarevisited 翻译: ImportNew.com Calarence
译文链接: http://www.importnew.com/14229.html

转载于:https://my.oschina.net/weaver/blog/1504392

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值