Backend Development 15 min read

Mastering Java Exception Handling: From Basics to Advanced Practices

This article explores Java's exception hierarchy, demonstrates proper use of try‑catch‑finally and return statements, shows how to define custom system, business, and third‑party exceptions, implements global handling with @RestControllerAdvice, and discusses monitoring and alerting strategies for robust backend development.

macrozheng
macrozheng
macrozheng
Mastering Java Exception Handling: From Basics to Advanced Practices

1. Introduction

During program development, exception handling is a complex dimension that developers of all levels must face; exceptions reflect system defects and optimization points, and cannot be completely avoided. Proper handling and reduction of exception frequency are fundamental to system quality.

2. Exception Hierarchy

Java's exception hierarchy includes:

Throwable : Superclass of all errors and exceptions.

Error : Typically unrecoverable, serious errors that cause the JVM to terminate the thread.

Exception : Exceptions that can be caught and handled by the program.

Exceptions are divided into checked and unchecked exceptions.

Checked Exception : Detected at compile time; must be caught or declared, otherwise compilation fails.

Unchecked Exception : Detected at runtime; may be thrown during execution.

3. Exception Usage

3.1 Details

Java exception handling keywords are:

try

(code block that may throw),

catch

(captures exceptions),

finally

(always executed),

throw

(throws a specific exception), and

throws

(declares thrown exceptions).

<code>public class UseExe01 {
    public static void main(String[] args) {
        try {
            strStm();
            ioStm();
        } catch (NullPointerException e) {
            System.out.println("空指针异常:" + e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            System.out.println("IO流异常:" + e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            System.out.println("异常:" + e.getMessage());
            e.printStackTrace();
        } finally {
            System.out.println("execute...finally");
        }
    }
    public static void ioStm() throws FileNotFoundException {
        new FileInputStream(new File("file_path"));
    }
    public static String strStm() throws NullPointerException {
        Object object = new Object();
        return object.getClass().getName();
    }
}
</code>

3.2 Return Value Issues

When

return

appears in

try

,

catch

, or

finally

, the actual returned value depends on the execution flow.

3.2.1 Primitive Types

<code>public class UseExe02 {
    // Returns 2
    public static int getInt1() {
        try {
            int i = 1 / 0;
        } catch (ArithmeticException e) {
            e.printStackTrace();
            return 1;
        } finally {
            System.out.println("execute...finally");
            return 2;
        }
    }
    // Returns 1
    public static int getInt2() {
        int a = 1;
        try {
            int i = 1 / 0;
            return a;
        } catch (ArithmeticException e) {
            e.printStackTrace();
            return a;
        } finally {
            ++a;
            System.out.println("execute...finally");
        }
    }
    // Returns 3
    public static int getInt3() {
        int a = 1;
        try {
            int i = 1 / 0;
            a++;
            return a;
        } catch (ArithmeticException e) {
            a++;
            e.printStackTrace();
        } finally {
            a++;
            System.out.println("execute...finally");
        }
        return a;
    }
}
</code>

3.2.2 Reference Types

<code>public class UseExe03 {
    // Returns 张三
    public static String getStr1() {
        String var;
        try {
            var = new String("张三");
            return var;
        } catch (ArithmeticException e) {
            e.printStackTrace();
        } finally {
            var = new String("李四");
            System.out.println("execute...finally:" + var);
        }
        return var;
    }
    // Returns 李四
    public static String getStr2() {
        String var;
        try {
            int i = 1 / 0;
            var = new String("张三");
            return var;
        } catch (ArithmeticException e) {
            e.printStackTrace();
            var = new String("李四");
            return var;
        } finally {
            var = new String("王五");
            System.out.println("execute...finally:" + var);
        }
    }
    // Returns 王五
    public static String getStr3() {
        String var;
        try {
            int i = 1 / 0;
            var = new String("张三");
            return var;
        } catch (ArithmeticException e) {
            var = new String("李四");
            e.printStackTrace();
        } finally {
            var = new String("王五");
            System.out.println("execute...finally:" + var);
        }
        return var;
    }
}
</code>

If only the

try

block contains a

return

, the value from

try

is returned.

If

try

throws and

catch

executes a

return

, that value is returned.

If the

finally

block contains a

return

, its value overrides previous returns when

finally

executes normally.

From a design perspective, using

return

inside

finally

is discouraged because it can prematurely terminate the method.

4. Project Practice

4.1 Exception Definition

In complex distributed systems, capturing exception information is crucial for rapid diagnosis and resolution. Two core dimensions are considered: capturing and solving exceptions, and propagating exception information to the client.

System Exception : e.g., timeout or service-level failures that require developer intervention.

Business Exception : User‑recoverable issues such as parameter validation or authorization problems.

Third‑Party Exception : Errors arising from interactions with external systems, encapsulated with unified response codes.

4.2 Exception Encapsulation

Define a base exception class extending

RuntimeException

:

<code>public class BaseExe extends RuntimeException {
    private String code;
    public BaseExe(String code, String msg) {
        super(msg);
        this.code = code;
    }
    public BaseExe(String message, Throwable cause) {
        super(message, cause);
    }
    // other constructors omitted
}
</code>

System exception and enum:

<code>public enum SysExeCode {
    SYSTEM_EXE("S00000", "系统异常");
}
public class SysException extends BaseExe {
    public SysException(String code, String msg) {
        super(code, msg);
    }
    public SysException(SysExeCode sysExeCode) {
        super(sysExeCode.getCode(), sysExeCode.getMsg());
    }
}
</code>

Business exception and enum:

<code>public enum BizExeCode {
    BIZ_EXE("B00000", "业务异常");
}
public class BizException extends BaseExe {
    public BizException(String code, String msg) {
        super(code, msg);
    }
    public BizException(BizExeCode bizExeCode) {
        super(bizExeCode.getCode(), bizExeCode.getMsg());
    }
}
</code>

Third‑party exception and enum:

<code>public enum ThirdExeCode {
    THIRD_EXE("T00000", "第三方异常");
}
public class ThirdException extends BaseExe {
    private String thirdCode;
    private String thirdMsg;
    public ThirdException(String code, String msg) {
        super(code, msg);
    }
    public ThirdException(String code, String msg, String thirdCode, String thirdMsg) {
        super(code, msg);
        this.thirdCode = thirdCode;
        this.thirdMsg = thirdMsg;
    }
    public ThirdException(ThirdExeCode thirdExeCode, String thirdCode, String thirdMsg) {
        super(thirdExeCode.getCode(), thirdExeCode.getMsg());
        this.thirdCode = thirdCode;
        this.thirdMsg = thirdMsg;
    }
}
</code>

4.3 Exception Handling

4.3.1 Response Method

Use

@RestControllerAdvice

and

@ExceptionHandler

for global exception handling:

<code>@RestControllerAdvice
public class ExeHandler {
    /** Default exception */
    @ExceptionHandler(value = Exception.class)
    public void defaultException(Exception e) {
        // unified response
    }
    /** System exception */
    @ExceptionHandler(value = SysException.class)
    public void sysException(SysException e) {
        // unified response
    }
    /** Business exception */
    @ExceptionHandler(value = BizException.class)
    public void bizException(BizException e) {
        // unified response
    }
    /** Third‑party exception */
    @ExceptionHandler(value = ThirdException.class)
    public void thirdException(ThirdException e) {
        // unified response
    }
}
</code>

4.3.2 Recording Method

Custom annotation + AOP is used to record logs, especially exception logs:

<code>@Component
@Aspect
public class LogAop {
    /** Log pointcut */
    @Pointcut("@annotation(com.defined.log.annotation.DefinedLog)")
    public void logPointCut() {}
    /** Around advice */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) {
        try {
            // execute method
            Object result = proceedingJoinPoint.proceed();
            return result;
        } catch (SysException e) {
            // system exception handling
        } catch (BizException e) {
            // business exception handling
        } catch (ThirdException e) {
            // third‑party exception handling
        } catch (Exception e) {
            // default exception handling
        } finally {
            // information processing
        }
        return null;
    }
}
</code>

4.4 Exception Notification

System and third‑party exceptions trigger immediate alerts to developers via messaging platforms (e.g., WeChat, DingTalk, email, SMS) for rapid diagnosis.

4.5 System Fault Analysis

Monitoring provides quick fault detection and analysis of request chains in distributed systems.

Request chain analysis visualizes complex call paths.

Log recording capabilities enable pinpointing issues and narrowing problem scope.

JavaAOPBackend DevelopmentException HandlingSpringBootCustom Exceptions
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.