概述

当方法内部发生一项错误时,该方法会创建一个对象传递给运行时系统(runtime system),这个对象被称为异常对象,包含错误的类型、发生位置,程序状态等一系列信息。

当一个方法抛出异常时,运行时系统会沿着调用栈(call stack)寻找该异常的处理方式 。

下图中,调用栈下面的方法调用了上面的方法,层层嵌套,一共四层:

调用第三个方法时抛出了一个异常,运行时系统就会沿着调用栈反向寻找该异常的处理程序,当该异常类型与某个异常处理程序声明的异常类型一致时,系统就将该异常交给它处理。

如果系统没能找到合适的异常处理程序,系统将会终止。

异常类型

java提供了两种处理异常的方式:

(1)   使用try语句捕获异常并处理;

(2)   使用throws关键字列出要抛出的异常类型,代表在本方法内不做处理,但是调用该方法的方法必须处理该异常或者继续抛出。

并不是所有异常都需要显式处理(这里的处理代表在程序内部捕获或者抛出),比如IOException、SQLException等是必须要处理的,而NullPointerException、ArithmeticException、IndexOutOfBoundsException等可以不作处理。

理解这一点,就要弄清异常的基本分类。

Checked Exception

这类异常是应用程序可以预见并能够恢复的错误,比如,应用程序需要用户输入一个文件名,然后程序将对这个文件进行读写操作。假如用户输入的文件名不存在,抛出java.io.FileNotFoundException,应用程序应该捕获这个异常并提醒用户。类似这种异常就属于checked exception。

除了Error、RuntimeException以及两者的子类,所有异常都属于checked exception

Error

Error一般来说是应用程序外部引起的异常,应用程序通常不能预见并恢复。比如,程序顺利打开了一个文件,但是由于硬件或者操作系统故障,不能够读取文件中的内容,程序就会抛出java.io.IOError。

Runtime Exception

runtimeexception一般来说是程序内部引起的异常,应用程序通常能够预见并恢复。这类异常的出现一般暗示程序存在bug。比如,还是文件操作的例子,由于逻辑错误,传入的文件名为空值,程序就会抛出一个NullPointerException。

虽然可以让程序捕获runtimeexception,但更合适的做法是剔除引起这类异常的bug。

java的异常类层次图如下:

异常的捕获

checked exception必须捕获,而unchecked exception的捕获不是必须的。例如:

import java.io.*;
import java.util.List;
import java.util.ArrayList;

public class ListOfNumbers {

    private List<Integer> list;
    private static final int SIZE = 10;

    public ListOfNumbers () {
        list = new ArrayList<Integer>(SIZE);
        for (int i = 0; i < SIZE; i++) {
            list.add(new Integer(i));
        }
    }

    public void writeList() {
         try{
         // FileWriter的构造方法 throws IOException, checked exception类型,必须捕获
        PrintWriter out = new PrintWriter(new FileWriter("OutFile.txt"));

        for (int i = 0; i < SIZE; i++) {
            // get(int)方法throws IndexOutOfBoundsException,RuntimeException的子类,unchecked exception类型,不是必须要捕获的
            out.println("Value at: "+ i + " = " + list.get(i));
        }
        out.close();
         }catch(IOException e){  //捕获IOException
                ...
         }
    }
}

unchecked exception在一些特殊的情况下也可以选择捕获它,比如上面的程序,现在既要捕获IOException,也要捕获IndexOutOfBoundsException,改写如下:

public void writeList() {
         try{
         // FileWriter的构造方法 throws IOException, checked exception类型,必须捕获
        PrintWriter out = new PrintWriter(new FileWriter("OutFile.txt"));

        for (int i = 0; i < SIZE; i++) {
            // get(int)方法throws IndexOutOfBoundsException,RuntimeException的子类,unchecked exception类型,不是必须要捕获的
            out.println("Value at: "+ i + " = " + list.get(i));
        }
        out.close();
         }catch(IndexOutOfBoundsException e){  //捕获IndexOutOfBoundsException
                ...
         }catch(IOException e){  //捕获IOException
                ...
         }

如果要同时捕获的异常存在继承关系,即某个异常时另一个异常的子类,必须把父类异常写在子类异常后面,否则会报编译错误。但是,无论有几个捕获语句,最终至多会进入一个catch语句。

例如:

public class Example {

      public void test() throws IOException{
             throw new IOException();
      }

      public static void main(String args []){

             Example example  = new Example();

             try {
                    example.test();
             } catch (IOException e) {
                    System.out.println("捕获了子类异常");
             } catch (Exception e) {
                    System.out.println("捕获了父类异常");
             }

      }

}

上例中,IOException是Exception的子类,如果方法抛出了IOException异常,会进入第一个catch子句,但不会进入第二个catch语句;如果抛出的是非IOException的其他Exception子类异常,则会直接进入第二个catch子句。也就是说,不会同时进入两个catch子句

从Java SE 7以后,一个catch块可以捕获多个异常,上面的捕获语句可简写为:

catch (IndexOutOfBoundsException | IOException ex) {
    ...
}

需要注意的是,这种情况下,catch的参数(上例中的“ex”)默认是final的,不能够在catch块中对它再次赋值。

无论异常是否发生,try代码块退出后,finally代码块都会执行,常常用于释放资源。例如:

public void writeList() {
       PrintWriter out = null;
    try{
      out = new PrintWriter(new FileWriter("OutFile.txt"));

      for (int i = 0; i < SIZE; i++) {
          out.println("Value at: " +i + " = " + list.get(i));
      }

    }catch(IOException e){
           ...
    }finally{  //释放资源
             if(out!=null){
                    out.close();
             }
    }
  }

上例中,有三种情况可导致try代码块退出:

(1)newFileWriter("OutFile.txt")抛出IOException

(2)list.get(i)抛出IndexOutOfBoundsException

(3)无异常抛出,代码执行完毕

无论发生了上面的那种情况,运行时系统都会保证finally代码块中的程序执行。

需要注意的是,如果在执行try-catch代码块的时候JVM退出了,或者执行try-catch代码块的线程被中断或者杀死,或者使用了System.exit()函数等,finally代码块有可能不被执行

带有返回值的函数中使用了try-catch-finally块,且返回值与是否发生异常有关,则应该避免将返回值写在finally块中,因为无论是否会发生异常,都会按照finally块的返回值,而忽略try-catch任何地方的返回值。例如:

public int test(){

             InputStream in = null;
             try {
                    File f = new File("F:\test.txt");
                    in = new FileInputStream(f);
                    return 1;
             } catch (IOException e) {
                    e.printStackTrace();
                    return 2;
             }finally{
                    try {
                           in.close();
                    } catch (IOException e) {
                           e.printStackTrace();
                    }
                    return 3;
             }
      }

上例中,无论是否会抛出IOException,都不会返回1或2,只会返回3。

try-with-resources语句

在try中声明的一个或多个资源,在程序结束后应该关闭,通常我们是在finally代码块中完成这项工作。

从java 7开始,提供了一种更为简洁有效的写法: try-with-resources语句。

使用形式如下:

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

try-with-resources确保{}内的程序执行完毕后自动关闭资源,所有实现了java.lang.AutoCloseable接口(java 7新增的接口,java.lang.Closeable的父接口,)的对象都可以当作资源。

throw与throws

捕获异常的前提是有方法抛出了异常。

throw关键字用于在方法体内部,发生错误的地方抛出异常。如:

public Object pop() {
    Object obj;

    if (size == 0) {  //栈为空,抛出异常
        throw new EmptyStackException();
    }

    obj = objectAt(size - 1);
    setObjectAt(size - 1, null);
    size--;
    return obj;
}

该方法用于从栈中弹出栈顶元素,但是,如果栈为空就不能进行这项操作,所以就会抛出EmptyStackException异常。

当其他方法调用pop()方法时,就应该考虑到pop()可能会抛出的异常,如果如果pop()抛出的UncheckedException,可以不做额外的处理;如果pop()抛出的是checked Exception则必须进行处理,可以用try-catch捕获,也可以选择在本方法内不做捕获,继续用throws关键字抛出,如:

public void callPop() throws EmptyStackException {
      ...
      pop(); //该方法可能会抛出EmptyStackException
      ...
}

实际上,一个异常很多时候是由于另一个cause异常引起的,因为cause 自身也会有 cause,依此类推,就形成了链式异常(Chained Exceptions)。例如:

try {

} catch(IOException e) {  //捕获到IOException时,抛出另一个异常

throw new SampleException("Other IOException", e);

}

Throwable有一种造函数可以接受Throwable类型的参数作为引起该异常的cause,Throwable类的initCause(Throwable)、getCause()可以设置cause信息、获取cause信息。

java异常拾遗的更多相关文章

  1. Java基础拾遗(二)

    (尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76358523冷血之心的博客) 马上就要秋招了,新的一轮笔试面试马上 ...

  2. Java基础拾遗(一)

    (尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76358391冷血之心的博客) 马上就要秋招了,新的一轮笔试面试马上 ...

  3. 浅谈java异常[Exception]

    学习Java的同学注意了!!! 学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:589809992 我们一起学Java! 一. 异常的定义 在<java编程思想 ...

  4. 基础知识《十》java 异常捕捉 ( try catch finally ) 你真的掌握了吗?

    本文转载自  java 异常捕捉 ( try catch finally ) 你真的掌握了吗? 前言:java 中的异常处理机制你真的理解了吗?掌握了吗?catch 体里遇到 return 是怎么处理 ...

  5. Java异常体系及分类

    上图是基本的java异常体系结构. 主要分为2大类:Error和Exception 1.Error:描述了Java运行系统中的内部错误以及资源耗尽的情形.应用程序不应该抛出这种类型的对象,一般是由虚拟 ...

  6. Java异常之自定义异常

    哎呀,妈呀,又出异常了!俗话说:"代码虐我千百遍,我待代码如初恋". 小Alan最近一直在忙着工作,已经很久没有写写东西来加深自己的理解了,今天来跟大家聊聊Java异常.Java异 ...

  7. 第11章 Java异常与异常处理

    1.Java异常简介 1.什么是异常异常出现的时候代码会无法正常运行下去,会产生各种问题2.捕捉异常的作用提早发现异常,方便查找问题,并给出解决方法3.Java中的异常1.Java中所有不正常的类都是 ...

  8. java 异常

    1.java异常 2.自定义抛出 3.运行时异常,程序有问题,让使用者可以改' ' 4.return  和  throw的区别 return 符合函数要求的值    throw  有问题的时候用它结束 ...

  9. 3.Java异常进阶

    3.JAVA异常进阶 1.Run函数中抛出的异常 1.run函数不会抛出异常 2.run函数的异常会交给UncaughtExceptionhandler处理 3.默认的UncaughtExceptio ...

随机推荐

  1. 集合之ArrayList的源码分析

    转载请注明出处 一.介绍 对于ArrayList,可以说诸位绝不陌生,可以说是在诸多集合中运用的最多一个类之一,那么它是怎样构成,怎样实现的呢,相信很多人都知道数组构成的,没毛病,如果遇到面试的时候, ...

  2. UWP中的文件相关操作

    最近开始做UWP开发,图省事儿就把自己之前一个Winform项目的一部分代码拷贝到了新写的UWP项目中来.整出了一些幺蛾子,下面做一个记录. 首先提一个重点就是:UWP里关于文件的操作尽量用Stora ...

  3. geotrellis使用(三十九)COG 写入更新

    前言 前面介绍过了如何在 ETL 的时候更新 Layer,使得能够在大数据量的时候完成 ETL 操作,同时前两篇文章也介绍了 COG 以及如何在 Geotrellis 中实现 COG 的读取.本文介绍 ...

  4. [LeetCode] Largest Number At Least Twice of Others 至少是其他数字两倍的最大数

    In a given integer array nums, there is always exactly one largest element. Find whether the largest ...

  5. [LeetCode] Maximum Vacation Days 最大化休假日

    LeetCode wants to give one of its best employees the option to travel among N cities to collect algo ...

  6. 【Swift】IOS开发中自定义转场动画

    在IOS开发中,我们model另外一个控制器的时候,一般都使用默认的转场动画. 其实我们可以自定义一些转场动画.达到不同的转场效果. 步骤如下:(photoBrowser是目标控制器) 1.在源控制器 ...

  7. Hibernate--对象关系

    在hibernate中,关联关系映射分为单向关联和双向关联.共有七种关系 ·@Many To One ·@One To Many(单向) ·@One To Many(多向) ·@One To One( ...

  8. python学习记录 - python3.x中如何实现print不换行

    python3.x中如何实现print不换行   大家应该知道python中print之后是默认换行的, 那如何我们不想换行,且不想讲输出内容用一个print函数输出时,就需要改变print默认换行的 ...

  9. poj 1046 ——Color Me Less

    提交地址:http://poj.org/problem?id=1046 Color Me Less Time Limit: 1000MS   Memory Limit: 10000K Total Su ...

  10. python 网络爬虫(一)爬取天涯论坛评论

    我是一个大二的学生,也是刚接触python,接触了爬虫感觉爬虫很有趣就爬了爬天涯论坛,中途碰到了很多问题,就想把这些问题分享出来, 都是些简单的问题,希望大佬们以宽容的眼光来看一个小菜鸟