单纯的使用Optional并不能很好的解决业务中的NPE问题

Scroll Down

工作中经常会遇到NPE(NullPointException)问题怎么处理,得到最多的回答就是Optional来处理,但是单纯的使用Optional并不能很好的解决业务中的NP问题。所以整理出日常工作中处理NPE问题的思路,供参考。
先看一下思路:

避免的操作

避免入参使用 Optional

日常工作中有是看到如下代码。

public void execute(Optional<String> nameOptional) {
   ...
}

如果方法的某个参数可能为null,那么可以使用方法重载,而不是传入一个null。因为代码的实现上揭示业务意图要要好于只表示业务意图,因为在业务上null没有业务意义,如果出现null,而又需要处理相关逻辑,那么可以使用方法重载。

另外,方法调用者将很清晰起作用的参数,也不需要为了调用某个方法而构造Optional。

public void execute() {
     execute(null);
}

public void execute(String name) {
    ...
}

上面的代码避免了对外方法的意图模糊,同时也避免了部分的重复代码。

避免多行 if() 语句

“使用了Optional,也没有感觉逻辑变变简单啊,每次都得get()方法”,这是工作中听到的刚刚接触Optional的开发人员的表述。

问题在哪里呢?如果我们有一把把核桃夹子,但是每次用这把核桃夹子做的事情都是砸核桃,那么就发现和用锤子砸也没有什么区别,结果都是碎了一地。

我们都说代码时重构出来的,而不是设计出来的。所以实现的时候如果对Optional不熟悉可以使用if来判断,重构的时候可以试着寻找一些能够有更好的解决办法。因为switch语句本来就是坏味道,寻找的方向可以先看看Optional除了提供了get方法,还提供了哪些方法,它们都是做什么用途的。

如何做

使用返回值中用Optional显式处理

如果实际实现中需要我们将null值返回,我们可以return一个Optioanl对象回去,这样该方法的调用者就必须就知道返回中有可能为null,并对其进行特定的处理。

public Optional<Data> execute() {
    ...
	return Optional.empty();
}

适当的时候使用Exception

并不是找不到结果我们就只能选择返回Optiona.empty(),除非逻辑需要继续执行而不期望中断,否则我们可以直接选择抛出异常。

例如,根据username、password寻找用户的方法,如果找不到用户,可以直接抛出InvalidUsernameOrInvalidPasswordException。

public User login(String name, String password) {
	...
	
	throw new InvalidUsernameOrInvalidPasswordException();
}

那么,外层要么进行异常处理,要么Project进行全局异常捕获,统一进行处理。

使用Optional Lambda

在01.02中提到了因为对Optional提供的方法不熟悉,而感觉和null值判断没有多大区别。那么推荐根据业务场景来选择Optioanl Lambda的写法。

String name = computer.flatMap(Computer::getSoundcard)
	.flatMap(Soundcard::getUSB)
	.map(USB::getVersion)
 	.orElse("UNKNOWN");

上面写法要比下面的写法清晰很多。当然这需要保持好奇心,多学习一点工具类提供的方法,同时别总是制作简单的搬砖工作。

String version = "UNKNOWN";
if (computer != null) {
	Soundcard soundcard = computer.getSoundcard();
	if (soundcard != null) {
		USB usb = soundcard.getUSB();
		if (usb != null) {
			 version = usb.getVersion();
 		}
 	}
}