From “The Programmer In the Middle of the Night.”

Author: wangzenghuang

preface

No matter in our work or life, there will always be all kinds of “mistakes”, all kinds of sudden “abnormal”. No matter how much preparation and testing we do, these exceptions will show up at some point, and if handled improperly or not in a timely manner, they will often lead to new problems. So be aware of these pitfalls and the need for a set of “best practices” to set up a sound exception handling mechanism.

The body of the

Abnormal classification

  


First of all, I’ve drawn a schematic of the anomaly classification.

In the JDK, Throwable is the parent class of all exceptions, divided into “Error” and “Exception”. Error means that a serious and uncontrollable Error occurred, such as an OutOfMemoryError. Exception is subdivided into two types. Check requires manual try/catch or throws in method definition. The compiler will check its validity during compilation. Uncheck does not need us to deal with it in advance. All of these simple concepts are essential for developers to master, so I’m going to show you an example without going into detail, but our “dinner” is still to come.

Reintroduce try/catch/finally

When it comes to exception handling, try/catch/finally has to be mentioned. A try cannot exist alone, either with a catch, finally, or all three.

1. Try code block: monitor the execution of the code block and jump to catch if the corresponding exception is found. If there is no catch, go directly to finally block.

2. Catch block: If an exception occurs, the code inside will be executed, either handled or thrown upwards.

3, finally code block: no matter whether there is an exception, must be executed, generally used to clean up resources, release connections, etc. However, there are several cases in which the code here will not be executed.

The code execution flow does not enter the try code block.

The code creates a death loop, deadlock, and so on in the try block.

The system.exit () operation is performed in the try block.

Try/catch/finally trap

Here are two pitfalls we may encounter when using TCF.

Code 1

public class TCFDemo {

public static void main(String[] args) {

/ / 11

System.out.println(returnVal());

}

static int returnVal(){

int a = 1;

int b = 10;

try{

return ++a;

}finally {

return ++b;

}

}

}

Trap 1: Adding a return statement in finally overwrites the value of the try code return. This is easy to trap if the business logic is complex.

Code 2

public class TCFDemo {

public static void main(String[] args) {

Lock lock = new ReentrantLock();

try{

// It is possible that the lock fails

lock.lock();

//dost

}finally {

lock.unlock();

}

}

}

Trap 2: Due to the lock method could throw at lock Uncheck exceptions, if in the try block, is bound to perform unlock method, at this time due to no locking is successful, so will be thrown IllegalMonitorStateException, This overwrites the failure of the former, so we should move the locking method outside the try block.

Best practices

Now that we’ve covered exception classification and try/catch/finally considerations, we can summarize our “best practices” for exception handling.

To throw an exception upwards, define an exception with service meaning based on the current service scenario. Exceptions defined in the industry or within the team are preferred. For example, DubboTimeoutException is thrown when a remote service call with Dubbo times out, rather than RuntimeException.

Do not use return statements in finally code blocks to avoid complicating the determination of returned values.

Catch Exception specific subclasses, not Exception, and certainly not throwable. This catches all errors, including serious errors thrown by the JVM that cannot be handled.

Don’t ignore any exceptions. Even if you can make sure that your logic works right now, you can’t make sure that your code will change in the future.

Do not use exceptions as a control flow, which is a very bizarre and performance-critical practice.

Clean up resources, release connections and other operations must be placed in finally code blocks to prevent memory leaks. If the finally block processes more logic and modular, we can encapsulate it into tool method calls, the code will be simpler.

At the end

Small exceptions, big knowledge, don’t you think?