Java (二):Tired Of Null Pointer Exception
Brief
A wise man once said you are not a real Java programmer until you’ve dealt with a null pointer exception. 没有处理过空指针,不算是真正的JAVA程序员
A NullPointerException at runtime and stop your program from running further.imagine if your program was running on a customer’s machine; what would your customer say if the program suddenly failed?
To give some historical context, Tony Hoare—one of the giants of computer science—wrote, “I call it my billion-dollar mistake. It was the invention of the null reference in 1965. I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement.
空指针造成十亿美元的损失 Let’s start with an example to see the dangers of Null. a nested object structure for a Computer, as illustrated:
String version = computer.getSoundcard().getUsb().getVersion();
How do avoid making NullPointerException ?
Verbose null check
API providers , irresponsible to return NULL directly.
Caller cautiously invoke API, afraid of making NullPointerException. Furthermore, it is an error-prone process; what if you forget to check that one property could be null?
Verbose null check, As a result, it’s just annoying that these checks get in the way of the business logic, they are decreasing the overall readability of our program and make code verbose and ugly. Caller每日疲于Check Null,难免烦躁. 正所谓 “埋头排雷心意烦, 怒向案板觅屠刀“
if (computer != null) { SoundCard soundCard = computer.getSoundCard(); if (soundCard != null) { Usb usb = soundCard.getUsb(); if (usb != null) { String version = usb.getVersion(); if (version != null) { System.out.print(version.toUpperCase()); } } } }
Force caller to handle checked exception
Caring API providers, throw Checked Exception when Object is null , force caller to handle exception explicity.You can no longer Forget To do It.
defined checked exception
public class DefinedObjectNullException extends Exception { public DefinedObjectNullException(String message) { super(message); } }
get SoundCard interface:
public SoundCard getSoundcard() throws DefinedObjectNullException { if(this.soundcard ==null){ throw new DefinedObjectNullException("soundCard is null"); } return soundcard; }
get Usb interface:
public Usb getUsb() throws DefinedObjectNullException { if(this.usb ==null){ throw new DefinedObjectNullException("Usb is null"); } return usb; }
get Usb’s version of Computer:
String usbVersion =null; try { SoundCard soundCard =computer.getSoundcard(); Usb usb =soundCard.getUsb(); usbVersion =usb.getVersion(); } catch (DefinedObjectNullException e) { LOGGER.error(e.getMessage()); usbVersion ="absent"; }
Use java8’s Optional explicitly
Optional as a single-value container that either contains a value or doesn’t (it is then said to be “empty”).
// soundcard maybe null,encapsulates an optional public OptionalgetSoundCard() { return Optional.ofNullable(soundCard); }
// Usb maybe null,encapsulates an optional public OptionalgetUsb() { return Optional.ofNullable(usb); }
// caller forced to check whether main object is null before use main object OptionaloptionalSoundCard = computer.getSoundCard(); if(optionalSoundCard.isPresent()){ SoundCard soundCard = optionalSoundCard.get(); Optional optionUsb =soundCard.getUsb(); if(optionUsb.isPresent()){ Usb usb=optionUsb.get(); System.out.print(usb.getVersion()); } }
Optional 与 Throw Checked Exception 实现意图相同,就实现方式而言:“前者Optional很友好、后者很粗暴”。
如果你还没尝java8,可以用Google Guava中Optional。
设计之初,尽量避免
“对外服务接口,杜绝return null”。服务接口提供者不要轻易“return null”。不然,调用者会小心翼翼使你的接口,生怕踩着雷。就算在接口文档中,写明接口可能返回Null,也难阻止调用者一时疏忽、忘记”check null”。所以,接口提供者如何处理“接口可能返回Null”的方式,就体现出个人情怀。
放任不管:直接return null。
好心好意:接口文档中写明可能会返回null。
不顾一切:接口提供者判断接口返回值,”IF null THEN throw checked Exception“,强迫调用者捕获、绝不让空指针冒出。
十全十美:针对接口可能返回null情况,通过Optional包装返回值,避免将null直接丢给调用者。这样,从编码层次,通过Optional标签更显著、更有效地警示调用者“接口可能返回Null”。
“设置对象属性,建议primitive type” 。 primitive type 自带默认值;非要是Object Type,建议手动设置默认值,因为Object Type这货缺省是null。
其次,对于对象属性值是对应表字段转换而来的情况(例如:Mybatis)。建议建表时,设置字段“not null Default ‘value’ “。这样,不仅可以提高表索引效率,而且不用提心吊胆使对象属性(属性是Object type类型)。