面试笔记03-Java基础(三):异常处理

一、异常的概念

Java语言中,异常是程序运行时出现的不正常或意外情况。

二、异常的分类

1. 异常的分类
答:
Java异常都继承自 Throwable,主要分两类:

  • Error:系统严重错误,如OutOfMemoryError(堆内存溢出错误),程序无法处理。
  • Exception:程序可处理异常,又分为:
    • 受检异常:编译时需处理,如IOException(输入输出异常)。
    • 非受检异常:编译时不强制处理,如NullPointerException(空指针异常)。

2. 受检异常和非受检异常在使用上有什么区别?
答:

  • 受检异常继承自 Exception。使用时:
    • 要么在方法内部使用 try-catch 捕获处理,
    • 要么在方法声明处使用 throws 关键字抛出,否则编译不通过。
  • 非受检异常继承自 RuntimeException。使用时:
    • 不需要在方法声明中显式抛出,
    • 也不强制要求在方法内部捕获,编译能正常通过。

3. 常见的Error、受检异常、非受检异常有哪些?
答:
常见 Error

  • StackOverflowError:栈溢出错误
  • OutOfMemoryError:内存溢出错误
  • NoClassDefFoundError:类定义未找到错误
  • LinkageError:链接错误

常见受检异常

  • IOException:输入输出异常
  • SQLException:数据库操作异常
  • ClassNotFoundException:类未找到异常
  • InterruptedException:线程中断异常

常见非受检异常

  • NullPointerException:空指针异常
  • ArrayIndexOutOfBoundsException:数组越界异常
  • ArithmeticException:算术异常
  • NumberFormatException:数字格式异常
  • IllegalArgumentException:非法参数异常
  • IndexOutOfBoundsException:索引越界异常

4. 分别给出一个Error、受检异常、非受检异常的简单示例代码。
答:
(1) Error 示例
StackOverflowError 属于 Error 类型,通常在方法无限递归调用时产生,因为每次方法调用都会在栈上分配空间,无限递归会使栈空间耗尽。

// 测试类
public class StackOverflowErrorExample {
    public static void recursiveMethod() {
        // 无限递归调用自身
        recursiveMethod();
    }

    public static void main(String[] args) {
        try {
            recursiveMethod();
        } catch (StackOverflowError e) {
            System.out.println("捕获到 StackOverflowError: " + e);
        }
    }
}

测试结果:

捕获到 StackOverflowError: java.lang.StackOverflowError

解释:
recursiveMethod 方法中,它不断地调用自身,没有终止条件,最终会导致栈空间耗尽,抛出 StackOverflowError。在 main 方法里,使用 try-catch 块捕获该错误并输出错误信息。

(2) 受检异常示例
IOException 是典型的受检异常,在进行文件操作、网络操作等可能发生输入输出问题的场景中经常出现,使用时必须进行处理。

import java.io.FileReader;
import java.io.IOException;

public class IOExceptionExample {
    public static void readFile() throws IOException {
        // 尝试打开一个文件进行读取
        FileReader reader = new FileReader("nonexistentfile.txt");
        int data;
        while ((data = reader.read()) != -1) {
            System.out.print((char) data);
        }
        reader.close();
    }

    public static void main(String[] args) {
        try {
            readFile();
        } catch (IOException e) {
            System.out.println("捕获到 IOException: " + e.getMessage());
        }
    }
}

测试结果:

捕获到 IOException: nonexistentfile.txt (系统找不到指定的文件。)

解释:
readFile 方法尝试打开一个不存在的文件 nonexistentfile.txt 进行读取,这会引发 IOException
由于 IOException 是受检异常,readFile 方法使用 throws 关键字声明抛出该异常。
main 方法中,调用 readFile 方法并使用 try-catch 块捕获并处理该异常。

(3) 非受检异常示例
NullPointerException 属于非受检异常,通常在尝试对一个 null 对象进行操作时抛出。

public class NullPointerExceptionExample {
    public static void main(String[] args) {
        String str = null;
        try {
            // 对 null 对象调用方法,会抛出 NullPointerException
            int length = str.length();
            System.out.println("字符串长度: " + length);
        } catch (NullPointerException e) {
            System.out.println("捕获到 NullPointerException: " + e);
        }
    }
}

测试结果:

捕获到 NullPointerException: java.lang.NullPointerException

解释:
main 方法中,定义了一个 null 的字符串对象 str,然后尝试调用它的 length() 方法,这会导致 NullPointerException 异常。使用 try-catch 块捕获并处理该异常。

三、try-catch-finally 语句

1. 简述 try-catch-finally 语句块中各部分的作用
答:

  • try 块包含可能抛出异常的代码;
  • catch 块用于捕获并处理 try 块中抛出的指定类型异常;
  • finally 块无论是否发生异常都会执行,常用于释放资源。

2. 在 try-catch-finally 结构中,如果 try 块中有 return 语句,finally 块中的代码会执行吗?
答:
会执行。
try 块遇到 return 语句时,会先保存返回值,然后执行 finally 块中的代码,最后再返回之前保存的值。

3. catch 块捕获异常后,若 finally 块中有 return 语句,会对 trycatch 块中的 return 结果有什么影响?
答:
finally 块中有 return 语句,会覆盖 trycatch 块中的 return 结果,最终返回 finally 块中 return 的值。

4. 请给出一个经典且简洁的try-catch-finally 语句的使用场景
答:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class TryCatchFinallyExample {
    public static void main(String[] args) {
        BufferedReader reader = null;
        try {
            // 尝试打开文件进行读取
            reader = new BufferedReader(new FileReader("test.txt"));
            String line;
            // 逐行读取文件内容并输出
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            // 捕获并处理可能出现的输入输出异常
            System.err.println("读取文件时出现错误: " + e.getMessage());
        } finally {
            try {
                if (reader != null) {
                    // 确保文件读取器被关闭
                    reader.close();
                }
            } catch (IOException e) {
                // 处理关闭文件读取器时可能出现的异常
                System.err.println("关闭文件读取器时出现错误: " + e.getMessage());
            }
        }
    }
}

代码解释

  • try 块: 代码尝试打开并读取文件 test.txt 的内容,将文件内容逐行输出。由于文件操作可能会出现异常,如文件不存在、文件无法访问等,所以这些操作被放在 try 块中。
  • catch 块:try 块中的代码抛出 IOException 时,catch 块会捕获该异常,并将错误信息打印到标准错误输出。
  • finally 块: 无论 try 块中是否发生异常,finally 块中的代码都会执行。在这个例子中,finally 块用于关闭文件读取器 BufferedReader,以确保资源被正确释放。关闭操作也可能会抛出 IOException,因此同样使用 try-catch 语句来处理。

四、自定义异常

1. 为什么需要自定义异常?
答:
在实际开发中,Java内置的异常类型可能无法精准描述业务场景中出现的问题。
自定义异常能使异常信息更具针对性,便于代码的维护和调试,让开发者可以根据业务需求对特定情况进行异常处理。

2. 简述自定义异常的步骤。
答:
(1) 创建一个类继承自 Exception(受检异常)或 RuntimeException(非受检异常)。
(2) 提供至少一个构造方法,通常包含一个接收异常信息字符串的构造方法。
(3) 若有需要,可添加其他自定义方法。

3. 给出一个经典的自定义异常的简单示例代码
答:
以下是一个自定义异常示例,模拟在一个简单的银行账户系统中,当尝试取款金额超过账户余额时抛出异常。(日常我们判定余额不足并不会使用异常抛出,这里只是作示例。)
自定义异常类

// 自定义异常类(余额不足异常),继承自 Exception,属于受检异常
class InsufficientBalanceException extends Exception {
    // 构造方法,接收异常信息
    public InsufficientBalanceException(String message) {
        super(message);
    }
}

银行账户类

// 银行账户类
class BankAccount {
    // 成员变量:账户余额
    private double balance;

    // 构造方法,初始化账户余额
    public BankAccount(double initialBalance) {
        this.balance = initialBalance;
    }

    // 取款方法,可能抛出 InsufficientBalanceException 异常
    public void withdraw(double amount) throws InsufficientBalanceException {
        if (amount > balance) {
            // 当取款金额大于账户余额时,抛出异常
            throw new InsufficientBalanceException("余额不足,无法取出 " + amount + " 元。");
        }
        balance -= amount;
        System.out.println("成功取出 " + amount + " 元,当前余额为 " + balance + " 元。");
    }
}

测试代码

// 测试类
public class CustomExceptionTest {
    public static void main(String[] args) {
        // 创建一个初始余额为 1000 元的银行账户
        BankAccount account = new BankAccount(1000);

        try {
            // 尝试取款 1500 元
            account.withdraw(1500);
        } catch (InsufficientBalanceException e) {
            // 捕获并处理异常,输出异常信息
            System.out.println("捕获到异常: " + e.getMessage());
        }

        try {
            // 尝试取款 500 元
            account.withdraw(500);
        } catch (InsufficientBalanceException e) {
            System.out.println("捕获到异常: " + e.getMessage());
        }
    }
}

运行结果:

捕获到异常: 余额不足,无法取出 1500.0 元。
成功取出 500.0 元,当前余额为 500.0 元。

代码解释

  • 自定义异常类 InsufficientBalanceException:继承自 Exception,表示这是一个受检异常。它包含一个构造方法,用于接收异常信息并传递给父类。
  • 银行账户类 BankAccount:包含一个 balance 字段表示账户余额,以及一个 withdraw 方法用于取款。在 withdraw 方法中,如果取款金额大于账户余额,就会抛出 InsufficientBalanceException 异常。
  • 测试类 CustomExceptionTest:创建一个银行账户对象,分别尝试取款 1500 元和 500 元,并使用 try-catch 块捕获和处理可能抛出的 InsufficientBalanceException 异常。
版权声明:本文《面试笔记03-Java基础(三):异常处理》是由陶其原创撰写,首发于陶其的个人博客
转载声明:如需转载本文,请务必在转载处保留原文链接:https://www.tqazy.com/?p=1343,并明确注明文章来源。
暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇