# 第1节:Nacos中的Optional的使用
在Java开发过程中经常会遇到空指针的问题,Java 8 API的出现,帮助我们提供了一个Optional的包装类,可以有效的防止代码中的空指针的问题。
先来看下Optional的源代码:
public final class Optional<T> {
/**
* Common instance for {@code empty()}.
*/
private static final Optional<?> EMPTY = new Optional<>();
/**
* If non-null, the value; if null, indicates no value is present
*/
private final T value;
private Optional() {
this.value = null;
}
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
public boolean isPresent() {
return value != null;
}
.....
}
从源代码中可以看到Optional类的主要职责就是帮助我们对原始对象进行了包装,进行了空值的判断,让我们的业务处理代码变得更佳优雅了。以前的代码中大量的判空让我们的代码有些丑陋。
再来看看Nacos中Optional是都怎么用的。
1、基于Derby的内存数据库的实现类EmbeddedStoragePersistServiceImpl
@Override
public long findConfigMaxId() {
String sql = "SELECT max(id) FROM config_info";
return Optional.ofNullable(databaseOperate.queryOne(sql, Long.class)).orElse(0L);
}
可以看到,这个在业务中也很常见,如果数量查询为空就付给一个默认值,这个也优雅的体现了拆箱的判断,以前写丑陋代码的时候,这块也很容易出现拆箱出现空值的问题。
2、基于SPI的加解密插件的处理器EncryptionHandler
public static Pair<String, String> encryptHandler(String dataId, String content) {
if (!checkCipher(dataId)) {
return Pair.with("", content);
}
String algorithmName = parseAlgorithmName(dataId);
Optional<EncryptionPluginService> optional = EncryptionPluginManager.instance()
.findEncryptionService(algorithmName);
if (!optional.isPresent()) {
LOGGER.warn("[EncryptionHandler] [encryptHandler] No encryption program with the corresponding name found");
return Pair.with("", content);
}
EncryptionPluginService encryptionPluginService = optional.get();
String secretKey = encryptionPluginService.generateSecretKey();
String encryptContent = encryptionPluginService.encrypt(secretKey, content);
return Pair.with(encryptionPluginService.encryptSecretKey(secretKey), encryptContent);
}
可以看到使用SPI加载了加密实现后,并optional.isPresent方法进行了判断。
3、JRaftServer类中invokeToLeader的异常判断
private void invokeToLeader(final String group, final Message request, final int timeoutMillis,
FailoverClosure closure) {
try {
final Endpoint leaderIp = Optional.ofNullable(getLeader(group))
.orElseThrow(() -> new NoLeaderException(group)).getEndpoint();
.......
} catch (Exception e) {
closure.setThrowable(e);
closure.run(new Status(RaftError.UNKNOWN, e.toString()));
}
}
可以看到该代码片段中使用orElseThrow方法优雅的进行了异常抛出处理。