# 第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方法优雅的进行了异常抛出处理。

Last Updated: 6/30/2022, 12:05:05 PM