Java异常处理 (try catch finally throw throws exception error)

本文详细介绍Java中的异常处理机制,包括异常分类、try-catch-finally语句的使用、throws和throw关键字的区别,以及如何合理地捕获和抛出异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址:http://chenxiaoqiong.com/articles/tryCatch/

异常分类

  
  Throwable是所有异常的基类,程序中一般不会直接抛出Throwable对象。Exception和Error是Throwable的子类,Exception下面又有RuntimeException和一般的Exception两类。可以把JAVA异常分为三类:

  • 检查性异常(非RuntimeException):所有继承自Exception并且不是RuntimeException的异常都是checked Exception。JAVA 语言规定必须对此类异常作处理,编译器会对此作检查,要么在方法体中声明抛出,要么使用catch语句捕获,不然不能通过编译。

  • 运行时异常(RuntimeException):与检查性异常相反, 编译器不会检查程序是否对RuntimeException作了处理。RuntimeException发生的时候,表示程序中出现了编程错误,所以应该找出错误修改程序,而不是去简单的捕获或者抛出。

  • 错误(Error): Error表示程序在运行期间出现了十分严重、不可恢复的错误,在这种情况下应用程序只能中止运行,例如JAVA 虚拟机出现错误。编译器不会检查Error是否被处理,在程序中不用捕获Error类型的异常;一般情况下,在程序中也不应该抛出Error类型的异常。

捕获异常try catch finally

在Java中,异常通过try-catch语句捕获。其一般语法形式为:

try {  
    // 可能会发生异常的程序代码  
} catch (Type1 id1) {  
    // 捕获并处理try抛出的异常类型Type1  
} catch (Type2 id2) {  
    // 捕获并处理try抛出的异常类型Type2  
} finally {  
    // 无论是否发生异常,都将执行的语句块  
}  

try 块:用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。
catch 块:用于处理try捕获到的异常。
finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。在以下4种特殊情况下,finally块不会被执行:
1)在finally语句块中发生了异常。
2)在前面的代码中用了System.exit()退出程序。
3)程序所在的线程死亡。
4)关闭CPU。
执行过程:当try捕获到异常,catch语句块里有处理此异常的情况:在try语句块中是按照顺序来执行的,当执行到某一条语句出现异常时,程序将跳到catch语句块,并与catch语句块逐一匹配,找到与之对应的处理程序,其他的catch语句块将不会被执行,而try语句块中,出现异常之后的语句也不会被执行,catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句;

抛出异常throw throws

throws关键字放在方法签名的尾部,一个方法可以声明抛出多个异常,多个异常之间用逗号隔开。如果一个方法可能会出现异常,但没有能力处理这种异常,则在方法声明处用throws子句来声明抛出异常。语法格式:

methodName throws Exception1,Exception2,.. 
{  
}  

当方法抛出上面的Exception1,Exception2,.. 异常时,方法将不对这些类型及其子类类型的异常作处理,而由调用该方法的调用者去处理。如果调用者不想处理该异常,可以继续向上抛出。如果所有方法都层层上抛获取的异常,最终JVM会进行处理(打印异常消息和堆栈信息)。

throw关键字总是出现在函数体中,用来抛出一个Throwable类型的异常。语法格式:

// 例如抛出一个IOException类的异常对象:
throw new IOException;

throw语句后的语句执行不到。如果抛出了检查异常,则还应该在方法头部声明方法可能抛出的异常类型。该方法的调用者也必须检查处理抛出的异常。

常用异常方法

下面的列表是 Throwable 类的主要方法:

方法名说明
public String getMessage()返回关于发生的异常的详细信息。这个消息在Throwable 类的构造函数中初始化了。
public Throwable getCause()返回一个Throwable 对象代表异常原因。
public void printStackTrace()打印toString()结果和栈层次到System.err,即错误输出流。
public String toString()使用getMessage()的结果返回类的串级名字。

常见异常

1. runtimeException子类:

异常说明
java.lang.ArrayIndexOutOfBoundsException数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
java.lang.ArithmeticException算术条件异常。譬如:整数除零等。
java.lang.NullPointerException空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等
java.lang.ClassNotFoundException找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。
java.lang.NegativeArraySizeException数组长度为负异常
java.lang.ArrayStoreException数组中包含不兼容的值抛出的异常
java.lang.SecurityException安全性异常
java.lang.IllegalArgumentException非法参数异常

2.IOException

异常说明
IOException操作输入流和输出流时可能出现的异常。
EOFException文件已结束异常
FileNotFoundException文件未找到异常

3. 其他

异常说明
ClassCastException类型转换异常类
ArrayStoreException数组中包含不兼容的值抛出的异常
SQLException操作数据库异常类
NoSuchFieldException字段未找到异常
NoSuchMethodException方法未找到抛出的异常
NumberFormatException字符串转换为数字抛出的异常
StringIndexOutOfBoundsException字符串索引超出范围抛出的异常
IllegalAccessException不允许访问某类异常
InstantiationException当应用程序试图使用Class类中的newInstance()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常

注意事项

  1. 子类抛出的异常必须是父类抛出异常的一个子集,不能抛出新异常。
  2. 不要让try块过于庞大
    • 阅读代码的时候,在try块冗长的代码中,不容易知道到底是哪些代码会抛出哪些异常,不利于代码维护。
    • 使用try捕获异常是以程序执行效率为代价的,将不需要捕获异常的代码包含在try块中,影响了代码执行的效率。
  3. finally语句块中不要抛出异常,不要使用return
      JAVA异常处理机制保证无论在任何情况下必须先执行finally块然后在离开try块,因此在try块中发生异常的时候,JAVA虚拟机先转到finally块执行finally块中的代码,finally块执行完毕后,再向外抛出异常。如果在finally块中抛出异常,try块捕捉的异常就不能抛出,外部捕捉到的异常就是finally块中的异常信息,而try块中发生的真正的异常堆栈信息则丢失了。
    例子:
public class TestException {
    public TestException() {
    }

    boolean testEx() throws Exception {
        boolean ret = true;
        try {
            ret = testEx1();
            return ret;
        } catch (Exception e) {
            System.out.println("testEx, catch exception");
            ret = false;
            throw e;
        } finally {
            System.out.println("testEx, finally; return value=" + ret);
        }
    }

    boolean testEx1() throws Exception {
        boolean ret = true;
        try {
            int b = 12;
            for (int i = 2; i >= -2; i--) {
                int c = b / i;
                System.out.println("i=" + i);
            }
            return true;
        } catch (Exception e) {
            System.out.println("testEx1, catch exception");
            ret = false;
            throw e;
        } finally {
            System.out.println("testEx1, finally; return value=" + ret);

            //此处抛出新的异常,将覆盖catch中抛出的异常
            //throw new Exception("testEx1, finally; throw new Exception");

            //此处return,catch中排出的异常将无法捕获
            return ret;
        }
    }

    public static void main(String[] args) {
        TestException testException1 = new TestException();
        try {
            testException1.testEx();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

    }
}

建议:当你需要一个地方来执行在任何情况下都必须执行的代码时,使用finally块。比如当你的程序中使用了外界资源,如数据库连接,文件等,使用finally块来释放资源。
4. 不要一次捕获所有异常

try
{
  method1();  //method1抛出ExceptionA
    method2();  //method1抛出ExceptionB
    method3();  //method1抛出ExceptionC
}
catch(Exception e)
{
    ……
}

这里有两个潜在的缺陷
- 分别处理就不能实现:针对try块中抛出的每种Exception,很可能需要不同的处理和恢复措施
- 代码中捕获了所有可能抛出的RuntimeException而没有作任何处理,掩盖了编程的错误,会导致程序难以调试。

正确代码:

try
{
  method1();  //method1抛出ExceptionA
    method2();  //method1抛出ExceptionB
    method3();  //method1抛出ExceptionC
}
catch(ExceptionA e)
{
    ……
}
catch(ExceptionB e)
{
    ……
}
catch(ExceptionC e)
{
    ……
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值