一、什么是异常?
异常是指在程序执行过程中出现的错误或异常情况。它可能是由于错误的输入、无效的操作、资源不可用等原因引起的。当程序遇到异常时,它会中断当前的执行路径,并转到能够处理该异常的代码块。
在 Java 中,异常是以对象的形式表示的,它们属于 Throwable 类或其子类的实例。Java 中的异常分为两种类型:
1、可检查异常(Checked Exception):这些异常在编译时就被检查到,要求在代码中进行处理或声明抛出。开发人员必须显式地处理这些异常或将其传播给调用者。常见的可检查异常包括 IOException、SQLException 等。
2、运行时异常(Runtime Exception):这些异常在运行时才会被抛出,不需要在代码中显式地进行处理或声明抛出。运行时异常通常由程序错误或错误的使用造成,如空指针引用、数组越界等。它们不要求进行强制性的处理,但良好的编程实践建议尽量避免运行时异常的发生。常见的运行时异常包括 NullPointerException、ArrayIndexOutOfBoundsException 等。
二、异常处理
在 Java 中,我们使用以下关键字来处理异常:
try:用于定义一个代码块,其中包含可能抛出异常的代码。
catch:用于捕获并处理指定类型的异常。
finally:用于定义一个代码块,无论是否发生异常都会执行其中的代码。
throw:用于手动抛出一个异常。try—catch—finally 的语法格式使用
try{
//选定捕获异常的范围,将可能出现异常的代码放在 try 语句块中
}
catch(异常类型1 变量名1){
//处理异常的方式1
}
catch(异常类型2 变量名2){
//处理异常的方式2
}
...
finally{
//一定会执行的代码
}
try
捕获异常的第一步是用 try{…} 语句块选定捕获异常的范围,将可能出现异常的代码放在 try 语句块中。
catch(可选)
在 catch 语句块中是对异常对象进行处理的代码。每个 try 语句块可以伴随一个或多个 catch 语句,用于处理可能产生的不同类型的异常对象。如果被捕捉的各类异常之间没有父子关系,各类的顺序无关紧要,如果有父子关系,应该将子类的 catch 块放置在父类的 catch 块之前。
finally(可选)
捕获异常的最后一步是通过 finally 语句为异常处理提供一个统一的出口,使得在控制流转到程序的其它部分以前,能够对程序的状态作统一的管理。不论在 try 代码块中是否发生了异常事件,catch 语句是否执行,catch 语句是否有异常,catch 语句中是否有 return,finally 块中的语句都会被执行。
下面是一个简单的代码示例,展示了异常处理的基本用法:
public class ExceptionHandlingExample {
public static void main(String[] args) {
try {
// 可能抛出异常的代码块
int result = divide(10, 0);
System.out.println("结果:" + result);
} catch (ArithmeticException e) {
// 捕获并处理指定类型的异常
System.out.println("除零错误:" + e.getMessage());
} finally {
// 无论是否发生异常,都会执行的代码块
System.out.println("异常处理完成。");
}
}
public static int divide(int dividend, int divisor) {
// 手动抛出异常
if (divisor == 0) {
throw new ArithmeticException("除数不能为零。");
}
return dividend / divisor;
}
}
在上面的示例中,divide() 方法可能抛出 ArithmeticException 异常,当除数为零时,我们手动抛出该异常。在 main() 方法中,我们使用 try-catch 块来捕获并处理这个异常。无论是否发生异常,finally 块中的代码都会执行。
三、自定义异常
除了使用 Java 标准库中定义的异常类,我们还可以自定义异常类来表示特定的错误或异常情况。自定义异常类通常继承自 Exception 或其子类,以便与其他异常区分开来。
以下是一个自定义异常类的示例:
public class MyException extends Exception {
private String message;
public MyException(){
super();
}
public MyException(String message){
super(message);
}
}
在这个示例中,MyException类继承自Exception类,并包含两个构造方法,一个无参构造方法和一个带有异常消息的有参构造方法。
接下来是TestException类,其中的test()方法声明了throws MyException,表示该方法可能会抛出MyException异常。在test()方法中,我们打印一条消息,并使用throw关键字抛出一个MyException异常,同时传入异常消息。
public class TestException {
public void test()throws MyException {
System.out.println("有错误吗");
throw new MyException("哎呀,出错了!");
}
}
在test()方法中,我们打印一条消息,并抛出一个MyException.
最后是主类Test,在该类的main方法中,我们创建一个TestException对象,并调用其test()方法。由于test()方法声明了throws MyException,我们需要在main方法的签名中使用throws MyException来处理可能抛出的异常。在异常被抛出时,程序会打印相应的异常消息。
public class Test {
public static void main(String[] args) throws MyException {
System.out.println("今天是个好日子");
TestException ex=new TestException();
ex.test();
}
}
改代码运行如下:
今天是个好日子
有错误吗
Exception in thread "main" Studying.MyException: 哎呀,出错了!
at Studying.TestException.test(TestException.java:6)
at Studying.Test.main(Test.java:7)
或者也可以使用RuntimeException,将TestException类和主类Test改为如下:
public class TestException {
public void test() {
System.out.println("有错误吗");
throw new RuntimeException();
}
}
public class Test {
public static void main(String[] args) throws MyException {
System.out.println("今天是个好日子");
TestException ex = new TestException();
try {
ex.test();
} catch (RuntimeException e) {
System.out.println("捕获到运行时异常");
}
}
}
这样也能正常运行,运行结果如下:
今天是个好日子
有错误吗
捕获到运行时异常
Process finished with exit code 0
由于test()方法会抛出RuntimeException,我们使用try-catch语句来捕获并处理这个异常。在异常被捕获时,会打印一条相应的消息。
通过这个示例,我们展示了自定义异常和异常处理的基本用法。自定义异常可以根据需要定义特定的异常类型,而异常处理可以帮助我们捕获并处理可能出现的异常情况,以确保程序的健壮性和稳定性。