【JAVA基础面经】JAVA中的异常

文章目录


前言

Java 异常机制是 Java 语言中用于处理程序运行时错误的一套完备体系。它将错误从正常的业务逻辑中分离出来,使得代码更健壮、可读性更高。下面从几个核心方面进行详细解释。

异常(Exception) 是指程序在执行过程中出现的非正常状况(例如除零、数组越界、文件不存在等)。Java 使用面向对象的方式来描述异常:每种异常都是 Throwable 类的子类的一个对象。当异常发生时,JVM 会创建一个异常对象,并抛出(throw);我们可以捕获(catch)并处理它。

JAVA异常体系结构

JAVA中的异常都来自于Throwable,Throwable 又派生出两个子类:一类是 Error 错误,另一类是 Exception 异常。其中 Error 指的是 JAVA 运行时内部错误和资源耗尽错误,这种内部错误一旦出现,除了告知用户并终止程序外别无他法。Exception又可以分为非受查异常(运行时异常)、受查异常(编译时异常)。

  • 受查异常 / 编译时异常:编译器强制要求处理(要么 try-catch,要么 throws)。例如 IOException、SQLException、ClassNotFoundException;
  • 非受查异常 / 运行时异常:即 RuntimeException 及其子类,编译器不强制处理。例如 NullPointerException、ArrayIndexOutOfBoundsException、ArithmeticException等。

JAVA中的异常处理方式

try-catch-finally

在 try 块中编写可能抛出异常的代码,使用一个或多个 catch 块捕获并处理特定类型的异常。finally 与 try 块配合,无论是否发生异常都会执行,用于释放资源(如关闭文件、数据库连接)。

java 复制代码
public class TryCatchFinallyDemo {
    public static void main(String[] args) {
        System.out.println("--- 基本 try-catch-finally ---");
        try {
            int result = 10 / 0;  // 抛出 ArithmeticException
            System.out.println("结果: " + result);
        } catch (ArithmeticException e) {
            System.out.println("捕获异常: " + e.getMessage());
        } finally {
            System.out.println("finally 块总是执行");
        }
    }
}

throws

throws 声明抛出,在方法签名中声明该方法可能抛出的异常类型,将异常处理责任转交给调用者。

java 复制代码
import java.io.*;

public class ThrowsDemo {
    // 声明可能抛出 IOException
    public static void readFile(String path) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(path));
        System.out.println(br.readLine());
        br.close();
    }

    public static void main(String[] args) {
        try {
            readFile("nonexistent.txt");
        } catch (IOException e) {
            System.out.println("调用者处理异常: " + e.getMessage());
        }
    }
}

throw

throw 手动抛出,在代码中主动创建并抛出一个异常对象(可以是 JDK 内置异常或自定义异常)。

java 复制代码
 public class ThrowDemo {
    public static void setAge(int age) {
        if (age < 0 || age > 150) {
            throw new IllegalArgumentException("年龄必须在 0~150 之间");
        }
        System.out.println("年龄设置为: " + age);
    }

    public static void main(String[] args) {
        setAge(25);   // 正常
        setAge(-5);   // 抛出异常
    }
}

自定义异常

对于自定义的异常,在声明时需要继承,继承Exception的为受查异常,继承RuntimeException的为非受查异常

java 复制代码
// 自定义受检异常
class MyCheckedException extends Exception {
    public MyCheckedException(String message) {
        super(message);
    }
}

// 自定义非受检异常
class MyUncheckedException extends RuntimeException {
    public MyUncheckedException(String message) {
        super(message);
    }
}

public class CustomExceptionDemo {
    public static void checkedMethod() throws MyCheckedException {
        throw new MyCheckedException("这是一个受检异常");
    }

    public static void uncheckedMethod() {
        throw new MyUncheckedException("这是一个非受检异常");
    }

    public static void main(String[] args) {
        try {
            checkedMethod();
        } catch (MyCheckedException e) {
            System.out.println(e.getMessage());
        }

        // 非受检异常可以不捕获(但会终止程序)
        uncheckedMethod();
    }
}

注意事项

避免在finally中使用return

尽量避免在finally中使用return,下面的程序中,程序先执行try中的代码,但最终还是会调用finally代码,从而将try中的代码进行了覆盖,最终返回20

java 复制代码
    public static int func(){
        int a = 10;
        try{
            return a;
        }catch (ArithmeticException e){
            e.printStackTrace();
        }finally {
            return 20;
        }
    }
    public static void main(String[] args) {
        System.out.println(func());//20
    }

受查异常 / 编译时异常不能单独使用 throw

如果一个方法内部可能抛出受查异常,那么该方法要么自己用 try-catch 捕获处理,要么在方法签名中用 throws 声明该异常。只用 throw 而不配合 throws 或 try-catch,编译会直接报错。

throw实际抛出一个异常对象,不满足编译器要求,它只是一个动作,没有处理也没有声明。

throw 必须与 throws 或 try-catch 配合

java 复制代码
//方式1 配合 throws(声明抛出)
public void methodWithThrows() throws IOException {
    throw new IOException();   // OK,因为方法声明了抛出 IOException
}
java 复制代码
//方式2 配合 try-catch(捕获处理)
public void methodWithCatch() {
    try {
        throw new IOException();   // 被 catch 接住,不会向外抛
    } catch (IOException e) {
        System.out.println("处理了异常");
    }
}

非受查异常 / 运行时异常可单独使用throw

对于 RuntimeException 及其子类(非受查异常),编译器不强制处理,所以可以单独使用 throw 而不加 throws 或 try-catch

java 复制代码
public void runtimeEx() {
    throw new NullPointerException();   // 编译通过,不需要 throws
}

Java 设计者希望通过编译时检查强制程序员处理受查异常,提高程序的健壮性。throw 只是抛出动作,并不包含任何"处理"语义。如果不强制配合 throws 或 try-catch,那么任何方法都可以随意抛出一个受查异常却不告知调用者,调用者也就无法预见和处理,受查异常就失去了意义。

相关推荐
ByteCraze2 小时前
JavaScript 深拷贝完全指南:从入门到精通
开发语言·javascript·ecmascript
wenzhangli72 小时前
ooderAgent 龙虾时代的统一认证体系
开发语言·php
一定要AK2 小时前
JVM 全体系深度解析笔记
java·jvm·笔记
coder阿龙2 小时前
基于SpringAI+Qdrant+Ollama本地模型和向量数据库开发问答和RAG检索
java·数据库·spring boot·ai·数据库开发
Gofarlic_OMS2 小时前
HyperWorks用户仿真行为分析与许可证资源分点配置
java·大数据·运维·服务器·人工智能
I Promise342 小时前
C++ 基础数据结构与 STL 容器详解
开发语言·数据结构·c++
morrisonwu2 小时前
kafka4.2对应php rdkafka扩展安装以及php的producer和consumer写法及避坑
开发语言·php
徒 花2 小时前
Python知识学习08
java·python·算法
Lyyaoo.2 小时前
【JAVA基础面经】== 和 equals() 的区别
java·开发语言·jvm