一、前言
null与NULL不都是表示空值吗?这有什么值得深入讨论的的?首先你在编写Java代码时使用过NULL吗?大概用IDE用习惯了,自动给生成以及纠正没有注意过也很正常。同样道理在数据库中的疑问我就不提问了。如果你不了解它们之间的区别,在Java操作数据库的时候,很有可能会出现一系列的BUG。
看下面我做的一个简单的测试:
实验一:使用null
实验二:使用NULL
预备知识:当声明了变量或者类却没有赋初值,Java会自动进行赋初值。赋值原则是整数类型int、byte、short、long的自动赋值为0,带小数点的float、double自动赋值为0.0,boolean的自动赋值为false,其他各种引用类型变量自动赋值为null。
二、Java中的null
首先声明,null是Java的关键字,并且大小写是敏感的。
Java是一种面向对象的高级编程语言,但是null本身不是对象,也不是Objcet的实例,null表示类或对象(包括字符串)是不存在的,不代表任何对象或实例,可以将null赋给引用类型变量,但不可以将null赋给基本类型变量;
与其对应,也是最为常见的一个异常:java.lang.NullPointerException
引发这个异常的情况有:
- 调用 null 对象的实例方法
- 访问或修改 null 对象的字段
- 将 null 作为一个数组,获得其长度
- 将 null 作为一个数组,访问或修改其时间片
- 将 null 作为 Throwable 值抛出
上面的所有情况都是null所引发的,只知其然,而不知其所以然是在开发中经常碰到这个异常的原因,要想尽量避免它,就必须深入的了解它。
2.1 大小写
因为null是大小写敏感的,所以Null,NULL等这类写法在Java代码中都是非法的。但是现在的IDE的功能太过于强大了,会自动修正或者填充,所以使用IDE基本不必考虑这个问题。
思考:因为IDE过于方便,使得我们会忽略很多细节,对于初学者而言建议从最简单的文本编辑器与命令行的方式进行学习。不要出现都学得挺多了,但是连一个main函数都敲不出来,那就尴尬了。
2.2 默认的初值
null是任何引用类型的默认值,不严格的说是所有object类型的默认值。这对所有变量都是适用的,如成员变量、局部变量、实例变量、静态变量(但当你使用一个没有初始化的局部变量,编译器会警告你)。
2.3 类型
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 |
null 可以赋值给引用变量,你不能将 null 赋给基本类型变量,例如int、double、float、boolean。但是可以赋值给他们的包装类类型,如上面的代码中使用的。
正如这个特性,也会导致一个异常的发生:先将 null 赋给包装类型,然后将包装类型赋值给基本类型,编译器完全是可以通过的,但是运行时会抛出空指针异常。
当然了编程的时候谁闲着没事这样做,但是很有可能无意中却这样做了,所以一定要谨慎。
这个异常时在自动拆箱的过程中,关于自动拆箱装箱可以参考《JAVA 包装类型 及 易错陷阱》。
2.4 对null的检查
== 与 !=
这种比较是最为常用的比较,但是也有其缺点。
something == null,这种写法完全没有任何异常,但是很容易失误导致错误。因为这种写法如果少一个等号,这样就变成了赋值,而代码仍然是可以正常运行的。所以更加安全的写法是 null == something,当我们将等号少写一个,会直接报异常,所以这种写法更加安全。
注意:不能使用其他算法或者逻辑操作,例如小于或者大于。
instanceof
Java 中的 instanceof 运算符是用来在运行时指出对象是否是特定类的一个实例。instanceof 通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例。
如果使用了带有 null 值的引用类型变量,instanceof 操作将会返回false。
1
2
3
4
5
6
|
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" ); } |
输出结果为:
iAmNull is NOT an instance of Integer
equals
在比较的时候除了 == 之外,我们经常会想到的就是 Object 类中就有的 equals() 方法,虽然许多类继承并覆盖了这个方法,但是大致上都差不多。因为Java中基本都是对象,所以都可以对其进行调用,一再强调null的类型(详见第一条),something.equals(null),当something不是null时一切正常,可是如果是null的话,会抛出空指针异常,你要是不嫌麻烦,完全可以捕获这个空指针异常,并直接做 null 处理,但是不建议。
1
2
3
4
5
6
7
8
|
public class ceshi{ static String a= null ; public static void main(String args[]){ if (a.equals( null )){ System.out.println( "==" ); } } } |
输出结果
Exception in thread "main" java.lang.NullPointerException
at ceshi.main(ceshi.java:6)
2.5 静态方法
你可能知道不能调用非静态方法来使用一个值为 null 的引用类型变量。它将会抛出空指针异常,但是你可能不知道,你可以使用静态方法来使用一个值为 null 的引用类型变量。因为静态方法使用静态绑定,不会抛出空指针异常。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public class ceshi{ public static void main(String args[]){ ceshi 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 ceshi.main(ceshi.java:6)
我们可以看到对象完全没有实例化但是却正常的执行了其静态的方法,这其实也不奇怪,静态方法完全可以使用类名直接使用,只不过绕了个弯,编译器,所以不足为奇。
2.6 参数传递
我们可以将null传递给方法使用,这时方法可以接收任何引用类型,例如public void print(Object obj)可以这样调用print(null)。从编译角度来看这是可以的,但结果完全取决于方法。Null安全的方法,如在这个例子中的print方法,不会抛出空指针异常,只是优雅的退出。如果业务逻辑允许的话,推荐使用null安全的方法。
2.7 用途
- 判断一个引用类型数据是否null。 用==来判断。
- 释放内存,让一个非null的引用类型变量指向null。这样这个对象就不再被任何对象应用了。等待JVM垃圾回收机制去回收。
三、SQL的NULL
在数据库中NULL表示 未知的。
NULL不等于零或空格,NULL 值不视作大于、小于或等于任何其它值。当一个变量、列或常量具有NULL值时,它的值是未知的、不确定的。“未知的”与空白或零或布尔值FALSE完全不同。“未知的”意味着该变量根本没有值,因此不能与其他变量直接进行比较。判断某列或者变量为 NULL 是只能用IS(NOT) NULL 去判断他的返回值是 true 还是 false。
NULL参与排序时总是作为最小值存在,即ORDER BY COL ASC时COL为NULL的行在最前面,反之在最后面。
NULL值是未知的,且占用空间,不走索引,DBA建议建表的时候最好设置字段是NOT NULL 来避免这种低效率的事情的发生。
NULL值具有以下三个规则:
- 一个NULL不与其他任何值相等;一个NULL不与其他任何值不等;
- 在对一个NULL值应用函数时,一般都会得到一个NULL值作为结果。
- 一般而言,只要执行涉及一个或多个NULL值的比较操作,那个比较的结果也是NULL值,它不同于TRUE或FALSE,因而这样的比较除了失败,没有任何帮助作用。
注意空值与NULL之间的差异:
- 在进行count()统计某列的记录数的时候,如果采用的NULL值,会被系统自动忽略掉,但是空值是会进行统计到其中的。(count(*)会将NULL统计上)
- 判断NULL 用IS NULL 或者 IS NOT NULL,SQL 语句函数中可以使用 ifnull() 函数来进行处理,判断空字符用 = 或者 <> 来进行处理。
- 对于MySQL特殊的注意事项,对于timestamp数据类型,如果往这个数据类型插入的列插入NULL值,则出现的值是NULL。插入空值,则会出现 '0000-00-00 00:00:00'
三、Java与SQL
Java中的 null 只能赋值给各种引用类型,不能赋值给基本类型,然而SQL中的可以将NULL赋给任何数据类型,因此这就会导致异常的出现。
这样一来,我们从数据库中读取字段的值后,在Java程序中如何判断读取的值是否为 null 呢?用 name==null 吗?显然不行,==是判断两个变量或实例是不是指向同一个内存空间,除非这个name是String类型的。而equals()方法呢?是判断两个变量或实例所指向的内存空间的值是不是相同。
java.sql.ResultSet接口中的boolean wasNull()方法可以解决这个问题:boolean wasNull();报告最后一个读取的列是否具有值 SQL NULL。
注意,必须首先对列调用一个获取方法尝试读取其值,然后调用wasNull ()方法查看读取的值是否为 SQL NULL。如果发生数据库访问错误将抛出SQLException。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://fanxiaobin.blog.csdn.net/article/details/52817928