java 异常处理

异常(Exception)也叫例外。在 java 编程语言中,异常就是程序运行过程中由于硬件设备问题,软件设计错误,缺陷导致的程序错误,在软件开发过程中,很多情况都会导致异常的产生。

  1. 想打开的文件不存在。
  2. 网络连接中断。
  3. 操作数超出预定范围。
  4. 正在装载的类文件丢失。
  5. 访问的数据库打不开。

可见,在程序中产生异常的现象是非常普遍的。在 Java 编程语言中,对异常的处理有非常完备的机制。异常本身作为一个对象,产生异常就是产生一个异常的对象。这个对象可能由应用程序本身产生,也可能由 Java 虚拟机产生,这取决于产生异常的类型。该异常对象中包括了异常事件的类型以及异常时应用程序目前的状态和调用过程。

Java 语言提供了两种处理异常的机制。

1:捕获异常
在 Java 程序运行过程中 系统得到一个异常对象时,它将会沿着方法的调用栈逐层回溯,寻找处理这一异常的代码。 找到能够处理这种类型异常的方法后,运行时系统把当前异常对象交给这个方法进行处理,这一过程称为捕获(Catch)异常。这是一种积极的异常处理机制。如果 java 运行时系统找不到可以捕获异常的方法,则运行时系统将终止,相应地,Java程序也将退出。

2:声明抛弃异常
当 Java 程序运行中系统得到一个异常对象时,如果一个方法并不知道如何处理所出现的异常,则可在该方法声明时,声明抛弃(Throws)异常。

异常类的类层次

前面已经提到过,Java 是采用面向对象的方法来处理错误的,一个异常事件时由一个异常对象来代表的。这些异常对象都对应于类 java.lang.Throwable 及其子类。

在 java 类库的每个包中都定义了自己的异常类,所有这些类都直接或间接地继承于类 Throwable.

java 中的异常事件分为两大类。一类继承于类Error .它的继承关键如下:
这里写图片描述

常见的错误类有:

  • AnnotationFormatError
  • AssertionError
  • AWTError
  • LinkageError
  • CodeMalfunctionError
  • FactoryConfigurationError
  • ThreadDeath
  • VirtualMachineError
  • TransformerFactoryConfigurationError
  • 包括动态链接失败,线程死锁,图形界面错误,虚拟机错误等。

通常 Java 程序不应该捕获这类异常,也不会抛弃这种异常。

另外一类异常则继承于类 Excetpion 这是 Java 程序中大量处理的异常。
这里写图片描述

常见的异常类有:

  • AclNotfoundException
  • ApplicationException
  • AWTException
  • BackingStoreException
  • ClassNotFoundException
  • CloneNotSupportedException
  • DataFormatException
  • DestoryFailedException
  • ExecutionException
  • PrintException
  • GeneralSecurityException
  • InterruptedException
  • InvalidPreferencesFormatException
  • ParseException
  • RuntimeException
  • SAXException
  • SQLException
  • TimeOutException
  • TransformerException
  • UnsupportedCallbackException
  • UnsupportedLookAndFeelException
  • URISyntaxException
  • UserException
  • XAException
  • XMLParseException
  • XPathException等

其中包括运行时异常和非运行时异常。

在类 Exception 之下还有一些子类,其中继承于 RuntimeException 的类代表了 Java 虚拟机在运行时所生成的异常,这类异常叫做运行时异常。由于这类异常事件的生成是很普遍的,要求程序对这类异常全部做成处理可能对程序的可读性和高效性带来不好的影响, 因此 Java编译器运行程序不对他们做出处理。

其它继承于类 Exception 的子类则代表非运行时异常。如 FileNotFoundException 和 IOException 。对于这类异常来说,如果程序不进行处理,可能会带来意想不到的结果,因此 java 编译器要求程序必须捕获或声明抛出这种异常。

常见的运行时异常:

(1)类型转换异常 ClassCastException

String strName = new String("123");
int nNumber = (int)StrName;

(2)数组超界异常 ArrayIndexOutBoundsException

int[] b = new int[10];
b[10] = 1000;

(3)指定数组维数为负值异常 NegativeArraySizeException

b[-1] = 1001;

(4)算术异常 ArithmeticException

int b = 0;
a = 500/b;

(5)Java 系统内部异常 InternalException

// JVM 抛出的异常

(6)类型不符合异常 IncompatibleTypeException

int n = 12345;
String s = (String) n;

(7)内存溢出异常 OutOfMemeoryException
(8)没有找到类定义异常 NoClassDefFoundException

aClass aa = new aClas(); // 但 aClass 类未定义

(9)空指针异常 NullPointerException

int b[];
b[0] = 99; // 没有实例化就访问,将产生空指针。

常见的非运行时异常:

(1)ClassNotFoundException :找不到类或接口所产生的异常。
(2)CloneNotSupportedException :使用对象的Clone 方法但无法执行 Cloneable所产生的异常。
(3)IllegalAccessException :类定义不明确所产生的异常。例如,类不为 public,或是包含一个类定义在另一个类库内。
(4)IOException:在一般情况下不能完成 I/O 操作所产生的异常。
(5)EOFException :打开文件没有数据可以读取所产生的异常。
(6)FileNotFoundException:在文件系统中,找不到文件名称或路径是所产生的异常。
(7)InterruptedIOException:目前现场等待执行,另一个线程中断目前线程 I/O 运行所产生的异常。

Throwable 类常用的方法

java.lang.Throwable 类是所有 Error 类和 Exception 类的父类,常用的方法有 :

1:public native Throwable fillInStackTrace()
填写执行堆栈跟踪信息。该方法在应用程序重新抛出错误或异常时有用。例如:

try{
    a = b/c;
}catch(ArithmeticThrowable e){
    a = Number.MAX_VALUE;
    throw e.fillInStackTrace();
}

2:public string getLocalizedMessage()
生成该 Throwable 的本地化描述。子类可能会覆盖该方法以便产生一个特定于本地的消息。对于未覆盖该方法的子类,默认返回调用 getMessage()的结果。

3:public String getMessage()
返回该 throwable 对象的详细。如果该对象没有详细信息则返回 null 。

4:public void printStackTrace()
把该 Throwable 和 它的跟踪情况打印到标准错误流。

5:public void printStackTrace(PrintStream s)
把该 Throwable 及其跟踪情况打印到指定打印流

6:public void printStackTrace( PrintWriter s)
把该 Throwable 及其跟踪情况打印到指定打印流

7:public String toSring()
返回该 throwable 对象的简短字符串描述。

异常的处理

对于运行时异常, java 编译器运行程序不对它们做出处理;但对于非运行时异常,则要求程序必须做捕获或声明抛出处理,否则是无法通过程序编译的。

捕获异常 try - catch - finally

一个方法中 如果对某种类型的异常对象提供了相应的处理代码,则这个方法可捕获该种异常。捕获异常时通过 try - catch - finally 语句实现的。语法为:

try{
    // ......
}catch(ExceptionName1 e){
    // ......
}catch(ExceptionName2 e){
    // ......
}finally{
    // ......
}

1.try
捕获异常的第一步是用 try{…} 选的捕获异常的范围,由 try 所限定的代码块中的语句在执行过程中可能会产生异常对象并抛弃。

2.catch
每个 try 代码块可以伴随一个或多个catch 语句,用于处理 try 代码块所生成的异常事件。 catch 语句只需要一个形式参数来指明它所能够捕获的异常类型,这个类必须是 Throwable 的子类,运行时系统通过参数值把被抛弃的异常对象传递给 catch 块。

catch 块中的代码用来对异常对象进行处理,与访问其他对象一样,可以访问一个异常对象的变量或调用它的方法。 getMessage() 是类 Throwable 所提供搞得方法,用来得到有关异常事件的信息, 类 Throwable 还提供了方法 printStackTrace() 用来跟踪异常事件发生时执行堆栈的内容。例如:

try{
    //....
}catch(FileNotFoundException e){
    System.out.println(e);
    System.out.println("message: " + e.getMessage());
    e.printStackTrace(System.out);
}catch(IOException e){
    System.out.println(e);
}

3. catch 语句的顺序
捕获异常的顺序和 catch 语句的顺序有关,当捕获到一个异常时,剩下的 catch 语句就不再进行匹配。因此,在安排 catch 语句的顺序时,首先应该捕获最特殊的异常,然后在逐渐一般化。 也就是说, 一般先安排子类,再安排父类。 例如上面的程序如果安排成如下的形式:

try{
    //....
}catch(IOException e){
    System.out.println(e);
    System.out.println("message: " + e.getMessage());
    e.printStackTrace(System.out);
}catch((FileNotFoundException e){
    System.out.println(e);
}

由于第一个 catch 语句首先得到匹配, 第二个语句将不会被执行。编译时将出现 “catch not reached” 的 错误提示信息。

4. filally

捕获异常的最后一步是通过 finally 语句为异常处理提供一个统一的出口,使得在控制流转到程序的其他部分以前,能够对程序的状态做统一的管理。一般是用来关闭文件或释放其他的系统资源。 虽然 finally 作为 try-catch-finally 结构的一部分,但在程序是可选的,就是说,可以没有 finally 语句。 如果存在 finally 语句,不论 try 块中是否发生了异常,是否执行过 catch 语句,都要执行 finally 语句。
另外, try - catch - finally 可以嵌套

声明抛弃异常

如果在一个方法中生成了一个异常,但是这一方法并不确切地知道该如果对这一异常事件进行处理,这时,该方法就应该声明抛弃异常,使得异常对象可以从调用栈向后传播,直到有合适的方法捕获它为止。

声明抛弃异常是在一个方法声明的 throws 子句中指明的。例如:

public int read() throws IOException{
    //....  
}

throws 子句中同时可以指明多个异常,之间由逗号隔开。例如:

public static void main(String[] args) throws IOException,IndexOutOfBoundsExecption{
    //....
}

最后 ,需要再次强调的是,对于非运行时异常,如前例中的 IOException 等, 程序中必须要做出处理,或者捕获,或者声明抛弃;而对于运行时异常,如前例中的 ArithmeticException, IndexOutOfBoundsException,则可以不做处理。

抛出异常的例子:

import java.io.*;

public class CatchDemo {
    public static void main(String[] args) throws FileNotFoundException,IOException{
            FileInputStream fis = new FileInputStream("text.txt");
            int b;
            while((b = fis.read()) != -1 ){
                System.out.println(b);
            }
            fis.close();
    }
}

在 main() 中 ,由于采用了抛弃 FileNotFoundException, IOException 异常的处理,在编译时就可以顺序通过了。如果 text.txt.文件存在,并且内容正常,那么程序可以正常运行。如果 text.txt 文件不存在或有其他问题,那么程序出现的异常将被提交给虚拟机处理。

捕获异常的例子:

import java.io.*;

public class CatchDemo {
    public static void main(String[] args) {
        try{
                 FileInputStream fis = new FileInputStream("text.txt");
                int b;
                while((b = fis.read()) != -1 ){
                    System.out.println(b);
                }
                fis.close();
        }catch(FileNotFoundException e){
            System.out.println(e);
            System.out.println("Message :" + e.getMessage());
            e.printStackTrace(System.out);

        }catch(IOException e){
            System.out.println(e);
        }
    }
}
// java.io.FileNotFoundException: text.txt (The system cannot find the file specified)
// Message :text.txt (The system cannot find the file specified)
// java.io.FileNotFoundException: text.txt (The system cannot find the file specified)
//  at java.io.FileInputStream.open0(Native Method)
//  at java.io.FileInputStream.open(FileInputStream.java:195)
//  at java.io.FileInputStream.<init>(FileInputStream.java:138)
//  at java.io.FileInputStream.<init>(FileInputStream.java:93)
//  at arraylistdemo.ArrayListDemo.main(ArrayListDemo.java:12)

抛出异常

抛出异常就是产生异常对象的过程,首先要生成异常对象,异常或者由虚拟机生成,或者由某些类的实例生成,也可以在程序中生成。 在方法中,抛出异常对象是通过 throw 语句实现的。
例如:

IOException e = new IOException();
throw e;

可以抛出的异常必须是 Throwable 或其子类的实例。下面的语句在编译时将会产生语法错误:

throw new String("throw anything");

自定义异常类必须是 Throwable 的直接或间接子类。
注意:一个方法所声明抛弃的异常是作为这个方法与外界交互的一部分而存在的,所以,方法的调用者必须了解这些异常,并确定如果正确地处理它们。

显示抛出异常详细的例子:

import java.io.*;

public class ExceptionDemo {
    public static void main(String[] args) {
        try{
            throw new Exception("my Exception");
        }catch(Exception e){
            System.err.println("Caught Exception");
            System.err.println("getMessage():" + e.getMessage());
            System.err.println("getLocalizedMessage():" + e.getLocalizedMessage());
            System.err.println("toString():" + e);
            System.err.println("printStackTrace():");
            e.printStackTrace();
        }
    }
}
// Caught Exception
// getMessage():my Exception
// getLocalizedMessage():my Exception
// toString():java.lang.Exception: my Exception
// printStackTrace():
// java.lang.Exception: my Exception
//   at ExceptionDemo.main(ExceptionDemo.java:12)

创建用户异常类

如果 java 提供的系统异常类型不能满足程序设计的需求,那么可以设计自己的异常类型。

从 java 异常类的结构测试可以看出, Java 异常的 公共父类为 Throwable.。 在程序运行中可能 出现两种问题:一种是由硬件系统或 JVM 导致的故障, Java 定义该故障为 Error, 这类问题是用户程序不能够处理的;另外一种问题是程序运行错误, Java 定义为 Exception, 这种情况下, 可以通过程序设计的调整来实现异常处理。

因此,用户定义的异常类型必须是 Throwable 的直接或间接子类。 Java 推荐用户的异常类型以 Exception 为直接父类。创建用户异常的方法如下:

Class UserException extends Exception{
    UserException(){
        super();
        // 其它语句
    }
}

在使用异常时,需要注意一下几点建议:

  1. 对于运行时例外,如果不能预测它何时发生,程序可以不做处理,而是让 Java 虚拟机去处理它。
  2. 如果程序可以预知运行时例外可能发生的地点和时间,则应该在程序中进行处理,而不应简单地把它交给运行时系统
  3. 在定义异常类时, 如果它所对应的异常事件通常总是在运行时产生的,而且不容易预测它将在何时,何处发生,则可以把它定义为运行时异常,否则定义为非运行时异常。

用户定义的异常类的使用

public class MyotherException extends Exception{
    public MyotherException(){

    }
    public MyotherException(String msg){
        super(msg);
    }
}

public class ExceptionDemo {
    public static void f()throws MyotherException{
        System.out.println("Throwing MyotherException form f()");
         throw new MyotherException();
    }
    public static void g() throws MyotherException{
        System.out.println("Throwing MyotherException form g()");
         throw new MyotherException("Originated in g()");
    }

    public static void main(String[] args) {
        try{
          f();
        }catch( MyotherException e){
          e.printStackTrace();
        }
         try{
          g();
        }catch( MyotherException e){
          e.printStackTrace();
        }
    }
}
// Throwing MyotherException form f()
// Throwing MyotherException form g()
// MyotherException 
//      at ExceptionDemo .f(ExceptionDemo .java:12)
//      at ExceptionDemo .main(ExceptionDemo .java:21)
//arraylistdemo.MyotherException: Originated in g()
//      at ExceptionDemo .g(ExceptionDemo .java:16)
//      at ExceptionDemo .main(ExceptionDemo .java:26)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值