Code review, something happened to Rui!

picture

Original: Miss Sister Taste (WeChat Public Account ID: xjjdog), welcome to share, please keep this statement for non-public account reprints.

Not long ago, the department had a code review.

The code is relatively simple as a whole, and the place where B should be blown has already been blown, it is nothing more than some old problems of if else. When I turned to the one-step execution code of a timed task, my eyes lit up, and I felt that it was time for a BB sentence.

Who knows that these guys were full of recognition during the judging, but soon after the judging ended, they gave me a 事Btitle.

Today, I will sort out these words at that time, and let everyone talk about whether I am a problem B. Gan!

An example of task processing

The structure of the code is roughly like this.

Through timing, this code reconciles the records of the database in the early morning every night. The main logic is to use an independent thread to progressively read the relevant records in the database, and then put these records in a loop for processing one by one.

ExecutorService service = Executors.newFixedThreadPool(10);
...
service.submit(()->{
    while(true){
        if(CollectionUtils.isEmpty(items)){
            break;
        }
        List<Data> items = queryPageData(start, end); // 分页逻辑
        for(Data item : items){
            try {
                Thread.sleep(10L);
            } catch (InterruptedException e) {
                //noop 
            }
            processItem(item);
        }
    }
});

复制代码

Wait a minute . When the code was turned over immediately, I called a stop, the exception here isprocessItem not caught .

Normally, this will not be a problem. But the quiet years are always interrupted by some random accidents. If this is the complete code for your task, it has a very obscure way of failing. Even if your unit tests are well written, we can still cause problems with this code through remote poisoning and problem logging.

Yes. The root cause of the above code is processItemthat the exceptions that may be generated by the function are not caught. If any one of the records throws an exception, no matter it is checkedan exception or uncheckedan exception, the execution of the entire task will be terminated!

Don't think it's simple, students who have stepped on this pit, please remember to deduct 666. Or look through your task execution code to see if you have this problem too.

The Java compiler will prompt you to catch exceptions in many cases, but some exceptions will always escape, such as null pointer exceptions. As shown in the figure below, both RuntimeException and Error are unchecked exceptions.

picture

RuntimeException可以不用try...catch进行处理,但是如果一旦出现异常,则会导致程序中断执行,JVM将统一处理这些异常。

你捕捉不到它,它自然会让你的任务完蛋。

如果你想要异步的执行一些任务,最好多花一点功夫到异常设计上面。在这上面翻车的同学比比皆是,这辆车并不介意再带上你一个。

评审的小伙很谦虚,马上就现场修改了代码。

不要生吞异常

且看修改后的代码。

ExecutorService service = Executors.newFixedThreadPool(10);
...
service.submit(()->{
    while(true){
        if(CollectionUtils.isEmpty(items)){
            break;
        }
        List<Data> items = queryPageData(start, end); // 分页逻辑
        for(Data item : items){
            try {
                Thread.sleep(10L);
            } catch (InterruptedException e) {
                //noop 
            }
            try{
                processItem(item);
            }catch(Exception ex){
                LOG.error(...,ex);
            }
        }
    }
});
...
service.shutdownNow();

复制代码

为了控制任务执行的频率,sleep大法是个有效的方法。

代码里考虑的很周到,按照我们上述的方式捕捉了异常。同时,还很贴心的把sleep相关的异常也给捕捉了。这里不贴心也没办法,因为不补齐这部分代码的话,编译无法通过,我们姑且认为是开发人员的水平够屌。

由于sleep抛出的是InterruptedException,所以代码什么也没处理。这也是我们代码里常见的操作。不信打开你的项目,忽略InterruptedException的代码肯定多如牛毛。

此时,你去执行这段代码,虽然线程池使用了暴力的shutdownNow函数,但你的代码依然无法终止,它将一直run下去。因为你忽略了InterruptedException异常。

当然,我们可以在捕捉到InterruptedException的时候,终止循环。

try {
    Thread.sleep(10L);
} catch (InterruptedException e) {
    break;
}

复制代码

虽然这样能够完成预期,但一般InterruptedException却不是这么处理的。正确的处理方式是这样的:

while (true) {
    Thread currentThread = Thread.currentThread();
    if(currentThread.isInterrupted()){
        break;
    }
    try {
        Thread.sleep(1L);
    } catch (InterruptedException e) {
        currentThread.interrupt();
    }
}

复制代码

除了捕捉它,我们还要再次把interrupt状态给复位,否则它就随着捕捉给清除了。InterruptedException在很多场景非常的重要。当有些方法一直阻塞着线程,比如耗时的计算,会让整个线程卡在那里什么都干不了,InterruptedException可以中断任务的执行,是非常有用的。

但是对我们现在代码的逻辑来说,并没有什么影响。被评审的小伙伴不满意的说。

还有问题!

有没有影响是一回事,是不是好的习惯是另一回事 。我尽量的装了一下B,其实,你的异常处理代码里还有另外隐藏的问题。

还有什么问题?,大家都一改常日慵懒的表情,你倒是说说

picture

我们来看一下小伙伴现场改的问题。他直接使用catch捕获了这里的异常,然后记录了相应的日志。我要说的问题是,这里的Exception粒度是不对的,太粗鲁。

try{
    processItem(item);
}catch(Exception ex){
    LOG.error(...,ex);
}

复制代码

processItem函数抛出了IOException,同时也抛出了InterruptedException,但我们都一致对待为普通的Exception,这样就无法体现上层函数抛出异常的意图。

比如processItem函数抛出了一个TimeoutExcepiton,期望我们能够基于它做一些重试;或者抛出了SystemBusyExcption,期望我们能够多sleep一会,给服务器一点时间。这种粗粒度的异常一股脑的将它们捕捉,在新异常添加的时候根本无法发现这些代码,会发生风险。

一时间会议室里寂静无比。

我觉得你说的很对 ,一位比较资深的老鸟说, 你的意思是把所有的异常情况都分别捕捉,进行精细化处理。但最后你还是要使用Exception来捕捉RuntimeException,异常还是捕捉不到啊

果然是不同凡响的发问。

优秀的、标准的代码写法,其中无法实施的一个重要因素,就是项目中的其他代码根本不按规矩来。如果我们下层的代码,进行了正确的空指针判断、数组越界操作,或者使用类似guava的Preconditions这类API进行了前置的异常翻译,上面的这种问题根本不用回答。

但上面这种代码的情况,我们就需要手动的捕捉RuntimeException,进行单独的处理。

Your project has too much rotten code, so it's hard to change it . Although I have emotional intelligence, I am more temperamental.

Everyone broke up.

End

I really can't figure it out, code review is used to find problems. As a result, this review will be opened, and everyone will ridicule me behind my back. Is this my problem? Or is it the team's problem? People don't understand.

I didn't say anything when you were wondering whether to use Integer or int. Now let's talk about exception handling, so glass heart can't stand it. You can't have all of these Bs installed.

What? Would you like to review my code? See if I actually write code like I say and lead by example? I'm sorry, I'm an architect, I haven't written code for many years.

Your wish has failed you!

picture

About the author: Miss Sister Taste (xjjdog), a public account that does not allow programmers to take detours. Focus on infrastructure and Linux. Ten years of architecture, tens of billions of daily traffic, discussing the high concurrency world with you, giving you a different taste. My personal WeChat xjjdog0, welcome to add friends for further communication.

Recommended reading:

1. Play Linux
2. What Taste Album

3.  Bluetooth is like a dream
4.  Murder!
5.  The architect who lost contact left only a script
6.  The bug written by the architect is unusual
7.  Some programmers are essentially a flock of sheep!

Miss sister taste

Don't envy mandarin ducks or immortals, just adjust a line of code for a long time

329 original content

Guess you like

Origin juejin.im/post/7080155730694635534