代码bad case


任何抛开场景对设计进行的评价都是愚蠢的。一个方案只要能实现目的都叫解决方案,解决方案没有对错,但是有好坏,我这里会总结一些我们在开发过程中所做的一些不好的设计、编码,包括管理方面愚蠢的举动。我会对入围的bad case进行场景的剖析,分析当时我们为什么会这么想,当然有些是我在采访当事人之后他们给出的说法。

try catch系列

for 循环内 try catch

这里本意是 forEach 针对每一个元素进行一个操作,该操作有可能会抛出异常,为了在for循环中不阻塞后面元素的执行,因此这里进行了try catch。一旦对元素的处理成功就加到一个成功的集合中并在最后进行返回。

但是,这里忽略了一点,就是失败的数据也被认为是成功的给加入到成功的list中进去了。

修改方式之一

mysql 系列

java中自定义的sql有必要全部大写么

有同事写代码的时候,特意把sql语句全部大写了。说是Mysql会默认转大写,如果全部写了大写就不用转了,提高性能。

网上的文章有的说可以提升性能,但是我问了一下Chat,回答如下,自己评判吧

CompletableFuture 系列

exceptionally 判断 e 是否为空

// exceptionally 中捕获判断 e 是否为空
public CompletableFuture<Boolean> addSealOneAsync(Object o, SealTypeEnum sealTypeEnum, String otherTemplateId, String batchCode) {
        String tenantId = TenantContext.getTenantId();
        return CompletableFuture.supplyAsync(() -> {
            TenantContext.setTenantId(tenantId);
            return addSealOne(o, sealTypeEnum, otherTemplateId, batchCode);
        }, threadPoolComponent.getSealGroupThreadPool()).exceptionally(e -> {
            if (e != null) {
                // 记录日志
                log.error("电子印章盖章异步任务异常。证明材料:{},印章类型:{},其他模板ID:{},批次号:{}", o, sealTypeEnum, otherTemplateId, batchCode, e);
            }
            return false;
        });
    }

首先,CompletableFuture 的 .exceptionally 注册的函数其本意是 当.supplyAsync发生异常的时候需要执行的方法,并且这个方法需要明确一下在异常时候的返回值。也就是说这个.exceptionally本意就是再遇到异常的时候给程序一个默认值,而不要再抛出异常。所以 e 一定不为空,这里判空是如此一举的。如下,直接记录日志并返回默认值即可。

public CompletableFuture<Boolean> addSealOneAsync(Object o, SealTypeEnum sealTypeEnum, String otherTemplateId, String batchCode) {
        String tenantId = TenantContext.getTenantId();
        return CompletableFuture.supplyAsync(() -> {
            TenantContext.setTenantId(tenantId);
            return addSealOne(o, sealTypeEnum, otherTemplateId, batchCode);
        }, threadPoolComponent.getSealGroupThreadPool()).exceptionally(e -> {
            // 记录日志
            log.error("电子印章盖章异步任务异常。证明材料:{},印章类型:{},其他模板ID:{},批次号:{}", o, sealTypeEnum, otherTemplateId, batchCode, e);
            return false;
        });
    }

exceptionally 捕获并抛出一个RuntimeException异常

//exceptionally 捕获并抛出一个RuntimeException异常
private CompletableFuture<Map<String, byte[]>> asyncDownloadOssFile(@NotNull OssPO oss, @NotBlank String fileName, @NotBlank String dir) {
        return CompletableFuture.supplyAsync(() -> {
            Map<String, byte[]> resultMap = new HashMap<>();
            resultMap.put(fileName, ossRpc.downloadRaw(oss, dir + fileName));
            return resultMap;
        }, threadPoolComponent.getArchiveThreadPool()).exceptionally(e -> {
            if (e != null) {
                throw new RuntimeException("异步下载文件失败!错误信息:" + e.getMessage(), e);
            }
            return null;
        });
}

首先,CompletableFuture 的 .exceptionally 注册的函数其本意是 当.supplyAsync发生异常的时候需要执行的方法,并且这个方法需要明确一下在异常时候的返回值。也就是说这个.exceptionally本意就是再遇到异常的时候给程序一个默认值,而不要再抛出异常。所以 e 一定不为空,这里判空是如此一举的。 那你说我不判空了,我按照下面这么写。

private CompletableFuture<Map<String, byte[]>> asyncDownloadOssFile(@NotNull OssPO oss, @NotBlank String fileName, @NotBlank String dir) {
        return CompletableFuture.supplyAsync(() -> {
            Map<String, byte[]> resultMap = new HashMap<>();
            resultMap.put(fileName, ossRpc.downloadRaw(oss, dir + fileName));
            return resultMap;
        }, threadPoolComponent.getArchiveThreadPool()).exceptionally(e -> {
            throw new RuntimeException("异步下载文件失败!错误信息:" + e.getMessage(), e);
            return null;
        });
}

这种写法连编译都通不过。因此你说那我再遇到异常的之后直接抛出一个RuntimeException,不写返回值了,这样总不会错了吧。当然编译不会出错,但是本来人家就抛出一个RuntimeException异常,你捕获了之后又抛出了一个RuntimeException异常,这不多此一举了么

private CompletableFuture<Map<String, byte[]>> asyncDownloadOssFile(@NotNull OssPO oss, @NotBlank String fileName, @NotBlank String dir) {
        return CompletableFuture.supplyAsync(() -> {
            Map<String, byte[]> resultMap = new HashMap<>();
            resultMap.put(fileName, ossRpc.downloadRaw(oss, dir + fileName));
            return resultMap;
        }, threadPoolComponent.getArchiveThreadPool()).exceptionally(e -> {
            throw new RuntimeException("异步下载文件失败!错误信息:" + e.getMessage(), e);
        });
}

这种写法,跟线面这种不写 exceptionally的写法本质上没有什么区别。所以结论就是,exceptionally 捕获并抛出一个RuntimeException异常 这种做法没有意义,可以不写。

private CompletableFuture<Map<String, byte[]>> asyncDownloadOssFile(@NotNull OssPO oss, @NotBlank String fileName, @NotBlank String dir) {
        return CompletableFuture.supplyAsync(() -> {
            Map<String, byte[]> resultMap = new HashMap<>();
            resultMap.put(fileName, ossRpc.downloadRaw(oss, dir + fileName));
            return resultMap;
        }, threadPoolComponent.getArchiveThreadPool())
}

如果非要较真,区别就是再捕获异常之后再异常的message中加了一个 "异步下载文件失败!错误信息:" 但这个信息对定位问题并没有给程序定位带来多大的帮助。如果这里不抛出一个RuntimeException而是抛出一个特定的自定义异常,然后再上层针对这个自定义的异常进行一个业务逻辑的处理,我还能接受,否则这里没有必要捕获这个异常。当然还有一个前提是,在外层调用这个一步方法之后,需要有join或者get方法,否则不捕获异常打印日志的行为会导致异常堆栈的丢失。


评论
  目录