Ten suggestions for Java exception handling

Posted Jun 15, 20206 min read

Foreword

Ten suggestions for Java exception handling, I hope to help everyone~

This article has been uploaded to github:

https://github.com/whx123/Jav...

Public account:Little boy picking up snails

1. Try not to use e.printStackTrace(), but use log printing instead.

Counterexample:

try{
  //do what you want
}catch(Exception e){
  e.printStackTrace();
}

Positive example:

try{
  //do what you want
}catch(Exception e){
  log.info("Your program is abnormal, {}",e);
}

reason:

  • The stack log printed by printStackTrace() is interleaved with the business code log, and it is usually not convenient to troubleshoot the exception log.
  • The string generated by the e.printStackTrace() statement records stack information. If the information is too long, the memory block where the string constant pool is located has no space, that is, the memory is full, then the user's request is stuck. ~

Second, the exception is caught, but the specific exception is not printed out, and the problem cannot be better located.

Counterexample:

try{
  //do what you want
}catch(Exception e){
  log.info("Your program is abnormal");
}

Positive example:

try{
  //do what you want
}catch(Exception e){
  log.info("Your program is abnormal, {}",e);
}

reason:

  • In the counter example, the exception was not taken out, and it is not easy to check the problem when it is time. Is it an exception of SQl writing error or an IO exception, or other? So you should print the exception to the log~

3. Don't use an Exception to catch all possible exceptions

Counterexample:

public void test(){
    try{
        //... code calls that throw IOException
        //... code calls that throw SQLException
    }catch(Exception e){
        //All possible exceptions captured with the base class Exception, if multiple levels are captured in this way, the valid information of the original exception will be lost
        log.info("Exception in test,exception:{}", e);
    }
}

Positive example:

public void test(){
    try{
        //... code calls that throw IOException
        //... code calls that throw SQLException
    }catch(IOException e){
        //Just catch IOException
        log.info("IOException in test,exception:{}", e);
    }catch(SQLException e){
        //Just catch SQLException
        log.info("SQLException in test,exception:{}", e);
    }
}

reason:

  • All possible exceptions caught with the base class Exception, if multiple levels are captured in this way, the valid information of the original exception will be lost

4. Remember to use finally to close the stream resource or directly use try-with-resource

Counterexample:

FileInputStream fdIn = null;
try {
    fdIn = new FileInputStream(new File("/jay.txt"));
    //Turn off streaming resources here? Is there any problem? What happens if something goes wrong?
    fdIn.close();
} catch(FileNotFoundException e) {
    log.error(e);
} catch(IOException e) {
    log.error(e);
}

Positive example 1:

Need to use finally to close the stream resources, as follows

FileInputStream fdIn = null;
try {
    fdIn = new FileInputStream(new File("/jay.txt"));
} catch(FileNotFoundException e) {
    log.error(e);
} catch(IOException e) {
    log.error(e);
}finally {
    try {
        if(fdIn != null) {
            fdIn.close();
        }
    } catch(IOException e) {
        log.error(e);
    }
}

Positive example 2:

Of course, you can also use the new feature of JDK7 try-with-resource to deal with, it is a new function provided by Java7, it is used for automatic resource management.

  • Resources refer to objects that must be closed after the program is used up.

  • try-with-resources ensures that each declared resource will be closed at the end of the statement

  • What kind of objects can be used as resources? Any object that implements the java.lang.AutoCloseable interface or java.io.Closeable interface is OK.

    try(FileInputStream inputStream = new FileInputStream(new File("jay.txt")) {

      //use resources

    } catch(FileNotFoundException e) {

      log.error(e);

    } catch(IOException e) {

      log.error(e);

    }

reason:

  • If you don't use finally or try-with-resource, when the program is abnormal and the IO resource stream is not closed, then this IO resource will be occupied by him, so that others can't use it, which causes waste of resources.

Fifth, catching exceptions and throwing exceptions must be an exact match, or catching exceptions is the parent class of throwing exceptions

Counterexample:

//BizException is a subclass of Exception
public class BizException extends Exception {}
//Throw parent Exception
public static void test() throws Exception {}

try {
    test(); //Compile error
} catch(BizException e) {//Catch exception subclasses cannot be matched
    log.error(e);
}

Positive example:

//Throw subclass Exception
public static void test() throws BizException {}

try {
    test();
} catch(Exception e) {
    log.error(e);
}

Sixth, the caught exception cannot be ignored, at least keep a log

Counterexample:

public static void testIgnoreException() throws Exception {
    try {
        //do things
    } catch(Exception e) {//No such exception

    }
}

Positive example:

public static void testIgnoreException() {
    try {
        //do things
    } catch(Exception e) {//No such exception
        log.error("This exception should not appear here,{}",e);
    }
}

reason:

  • Although it is an exception that does not occur under normal circumstances, if you catch it, don t ignore it, at least make a log~

7. Pay attention to the infection of exceptions on your code hierarchy(early detection and early treatment)

Counterexample:

public UserInfo queryUserInfoByUserId(Long userid) throw SQLException {
    //Query the database based on user ID
}

Positive example:

public UserInfo queryUserInfoByUserId(Long userid) {
    try{
        //Query the database based on user ID
    }catch(SQLException e){
        log.error("Query database is abnormal, {}",e);
    }finally{
        //Close the connection and clean up resources
    }
}

reason:

  • Our project generally divides the code into different hierarchical structures such as Action, Service, Dao, etc. If you are an exception handled by the DAO layer, deal with it as soon as possible. If you throw SQLException up, the upper layer code still needs to try catch. This pollutes your code~

8. Custom encapsulation exception, do not discard the original exception information Throwable cause

We often want to throw another exception after catching an exception, and hope to save the original exception information, which is called the exception chain. The company's framework provides unified exception handling and uses the exception chain. We customize the exception and don't discard the original exception information, otherwise it will be a headache to troubleshoot the problem

Counterexample:

public class TestChainException {
    public void readFile() throws MyException{
        try {
            InputStream is = new FileInputStream("jay.txt");
            Scanner in = new Scanner(is);
            while(in.hasNext()) {
                System.out.println(in.next());
            }
        } catch(FileNotFoundException e) {
            //e save exception information
            throw new MyException("Where is the file");
        }
    }
    public void invokeReadFile() throws MyException{
        try {
            readFile();
        } catch(MyException e) {
            //e save exception information
            throw new MyException("File not found");
        }
    }
    public static void main(String[]args) {
        TestChainException t = new TestChainException();
        try {
            t.invokeReadFile();
        } catch(MyException e) {
            e.printStackTrace();
        }
    }
}
//MyException constructor
public MyException(String message) {
        super(message);
    }

The running result is as follows, without Throwable cause, it is not easy to troubleshoot what is abnormal

Positive example:

public class TestChainException {
    public void readFile() throws MyException{
        try {
            InputStream is = new FileInputStream("jay.txt");
            Scanner in = new Scanner(is);
            while(in.hasNext()) {
                System.out.println(in.next());
            }
        } catch(FileNotFoundException e) {
            //e save exception information
            throw new MyException("Where is the file", e);
        }
    }
    public void invokeReadFile() throws MyException{
        try {
            readFile();
        } catch(MyException e) {
            //e save exception information
            throw new MyException("File not found", e);
        }
    }
    public static void main(String[]args) {
        TestChainException t = new TestChainException();
        try {
            t.invokeReadFile();
        } catch(MyException e) {
            e.printStackTrace();
        }
    }
}
//MyException constructor
public MyException(String message, Throwable cause) {
        super(message, cause);
    }

Nine, runtime exception RuntimeException, should not be handled by catch, but pre-check first, such as:NullPointerException handling

Counterexample:

try {
  obj.method()
} catch(NullPointerException e) {
...
}

Positive example:

if(obj != null){
   ...
}

Ten. Pay attention to the order of exception matching and prioritize the capture of specific exceptions

Pay attention to the matching order of exceptions, because only the first catch block that matches the exception will be executed. If you want to see that it is NumberFormatException, throw NumberFormatException, if it is IllegalArgumentException, throw IllegalArgumentException.

Counterexample:

try {
    doSomething("test exception");
} catch(IllegalArgumentException e) {
    log.error(e);
} catch(NumberFormatException e) {
    log.error(e);
}

Positive example:

try {
    doSomething("test exception");
} catch(NumberFormatException e) {
    log.error(e);
} catch(IllegalArgumentException e) {
    log.error(e);
}

reason:

  • Because NumberFormatException is a subclass of IllegalArgumentException, in the counter-example, no matter which exception it is, it will match IllegalArgumentException and it will not be executed anymore, so I don't know whether it is NumberFormatException. So you need to catch specific exceptions first, put NumberFormatException in front~

No public

  • Welcome to follow my personal public account, make a friend, and study together~
  • If the answer is wrong, welcome to point out, thank you very much~