java的异常处理机制能够使程序有极好的容错性,让程序更加的健壮.所谓的异常,就是指的阻止当前方法或作用域继续运行的问题,,当程序运行时出现异常时,系统就会自己主动生成一个Exception对象来通知程序.这样就极大的简化了我们的工作.

当然java的异常对象有非常多种,以下这幅图显示了java异常类的继承体系.

从图片中能够看到java将全部的非正常情况分成了两种: 异常(Exception)和错误(Error),他们都继承Throwable父类.Error错误通常是指与虚拟机相关的问题,如系统崩溃,虚拟机错误等.这样的错误无法恢复或不可捕获,将导致应用程序中断,通常应用程序无法处理这些错误,因此也不应该试图用catch来进行捕获.而对于Exception我们是能够进行捕获并处理的.以下从几个方面对异常处理机制进行介绍.

一.异常处理的一般格式

        try{
///可能会抛出异常的代码
}
catch(Type1 id1){
//处理Type1类型异常的代码
}
catch(Type2 id2){
///处理type2类型异常的代码
}

try块中放置可能会发生异常的代码(可是我们不知道详细是哪种异常).假设异常发生了,try块抛出系统自己主动生成的异常对象,然后异常处理机制将负责搜寻參数与异常类型相匹配的第一个处理程序,然后进行catch语句运行(不会在向下查找).看起来和switch语句比較相似.除了上面列出的那些异常类,事实上我们也能够自定义异常,然后处理他们.定义异常最重要的是异常类的名字,最好做到望名知义.另外异常处理中经常出现的throws和throw这两个关键字;throws表示的是当前程序不处理这个异常将其抛给调用这个程序的上一级程序运行,假设是main()方法则传给JVM虚拟机处理.throw表示的是显式的抛出一个异常对象.以下的代码中用到了上面提到的知识点.

///自定义一个简单的异常类,仅仅须要声明以下继承关系
///也能够自己编写构造器,但这不是必要的
public class SimpleException extends Exception{
///public SimpleException();
///public SimpleException(String str){
///super(str)};
} package lkl; import java.util.Scanner; public class ExceptionTest { ///声明该程序不处理SimpleException异常而是将其丢出
public void f() throws SimpleException{
System.out.println("Throws SimpleException from f()");
///丢出一个SimpleException异常对象
throw new SimpleException();
}
///多个try语句会依次运行,即使上一个try语句发生异常,下一个try语句任然会运行
public static void main(String[] args){
ExceptionTest et =new ExceptionTest();
try{
et.f();
}///处理try中丢出的SimpleException异常
catch (SimpleException sn){
System.out.println("Catch it");
//调用异常类的printStackTrace()方法,默认是打印到标准错误流的
///如今我们显示指定输出到标准输出流
///会打印从方法调用处直到异常抛出处的方法调用序列,栈顶是最后一次调用的而栈底是第一次掉用的
sn.printStackTrace(System.out);
}
try{
int[] a= new int[10];
Scanner sc = new Scanner(System.in);
System.out.println("请输入k: ");
int k=sc.nextInt();
sc.close();
System.out.println(a[k]);
}
///处理数组下标越界的异常
catch(ArrayIndexOutOfBoundsException ae){
System.out.println("Catch ArrayIndexOutOfBoundsException");
ae.printStackTrace(System.out);
}
}
}

二.打印异常信息

异常类的基类Exception中提供了一组方法用来获取异常的一些信息.所以假设我们获得了一个异常对象,那么我们就能够打印出一些实用的信息,最经常使用的就是void printStackTrace()这种方法,这种方法将返回一个由栈轨迹中的元素所构成的数组,当中每一个元素都表示栈中的一帧.元素0是栈顶元素,而且是调用序列中的最后一个方法调用(这个异常被创建和抛出之处);他有几个不同的重载版本号,能够将信息输出到不同的流中去.以下的代码显示了如何打印主要的异常信息:

package lkl;

///測试异常类Exception的经常用法
public class ExceptionMethods { public static void main(String[] args){
try{
throw new Exception("My Exception");
}///通过捕获异常类的基类Exception就能够捕获全部类型的异常
catch(Exception e){
System.out.println("Caught Exception");
System.out.println("getMessage(): "+e.getMessage());
System.out.println("getLocalizedMessage(): "+e.getLocalizedMessage());
System.out.println("toString(): "+e.toString());
System.out.println("printStackTrace(): ");
e.printStackTrace(System.out);
}
}
}

三.又一次抛出异常与异常链

有时候须要将捕获的异常又一次抛出,这样在语法上是非常easy的.但问题是假设直接抛出的话,这个异常对象中信息将仍然是原来异常对象中的信息.假设我们想要跟新一下这个信息,我们能够调用fillInStackTrace()方法,这种方法返回一个Throwable对象,它是通过将当前调用栈信息填入原来那个对象而得到的.调用fillStackTrace()的那一行就成了异常的新的发生地.假设我们在捕获了异常之后抛出了第二种异常,那么原来异常发生点的信息会丢失,得到与fillInStackTrace()一样的方法.

所谓的异常链指的是在捕获一个异常后抛出还有一个异常,而且希望把原始异常的信息给保留下来.java中的Throwable子类在构造器中都能够接受一个cause(因由)对象作为參数.这个參数事实上就是原先的异常对象,这样通过把原始异常传递给新的异常,使得即使在当前位置创建并抛出了新的异常,也能够通过异常链追踪到异常最初发生的位置.可是在Throwable的子类中,仅仅对Error,Exception,RuntimeException这三个子类提供了带cause因子的构造器,假设要把其他类型的异常链接起来,就应该使用initCause()方法而不是构造器了.

四.使用finally进行清理

引入finally语句的原因是我们希望一些代码总是能得到运行,不管try块中是否抛出异常.这样异常处理的基本格式变成了以下这样:

     try{
///可能会抛出异常的代码
}
catch(Type1 id1){
//处理Type1类型异常的代码
}
catch(Type2 id2){
///处理type2类型异常的代码
}
finally{
///总是会运行的代码
}

事实上catch和finally语句也能够仅仅有一个出现.以下的代码显示了finally语句总能运行

package lkl;

public class FinallyTest extends Exception{

    public static int count=0;
public static void main(String[] args){
while(true){
try{
//不管是不是抛出异常,finally语句都会运行
if(count++==0){
throw new MyException();
}
System.out.println("No exception");
}
catch(MyException me){
System.out.println("MyException");
}
finally{
System.out.println("In finally clause");
if(count==2) break;
}
}
}
}

以下这份代码说明就算在try中有return语句,finally语句仍会得到运行,看起来就像有多个返回点.

package lkl;

public class MultipleReturns {

    public static void f(int i){
System.out.println("Initialization that requires cleanup");
try{///在函数reutrn之前,finally回先运行
System.out.println("Point 1");
if(i==1) return ;
System.out.println("Point 2");
if(i==2) return ;
System.out.println("Point 3");
if(i==3) return ;
System.out.println("Point 4");
if(i==4) return;
}
///在上面的return之前,会先运行finally语句
finally{
System.out.println("Perferming cleanup");
}
}
public static void main(String[] args){
for(int i=1;i<=4;i++)
f(i);
}
}

那么总是会运行的finally语句用来干嘛?

在java中我们主要用来清理除内存外的其他一些资源,这些资源包含:已经打开的文件或网络连接,在屏幕上画的图像等.

五.异常处理与继承

最后一个问题是关于异常处理和继承的.当异常处理和继承一起发生的时候,我们须要关注的问题就是父类构造器抛出异常和子类构造器抛出异常的关系,在子类中重写父类方法是如何声明异常等问题.总结一下事实上也就是二个规则:

1).子类重写基类方法抛出的异常必须不比原基类方法抛出的异常类型更大.

2).尽管在语法上对子类构造器的异常声明没有规定,可是子类构造器的异常说明必须包含基类构造器的异常说明.(由于基类的构造器总是会被调用).

以下的代码对此进行了演示:

public class Foul extends BaseballException{
} public class PopFoul extends Foul{
} public class BaseballException extends Exception{
} public class Strike extends BaseballException{ } public class RainedOut extends StormException{ } public interface Storm { public void event() throws RainedOut;
public void rainHard() throws RainedOut;
} public abstract class Inning { public Inning() throws BaseballException{}
///定义抛出异常,可是实际上并没有
public void event() throws BaseballException{};
//声明抛出两个异常
public abstract void atBat() throws Strike ,Foul; public void walk() {}
} public class StormyInning extends Inning implements Storm{ public StormyInning() throws BaseballException,RainedOut{}
public StormyInning(String s)
throws Foul,BaseballException{}
//由于基类方法中没有抛出异常而子类覆盖后的方法抛出了
///所以编译报错
//void walk() throws PopFoul{} //接口不能给基类方法加入异常类型
//public void event() throws RainedOut{} ///重写的方法抛出和基类方法一样的异常是能够的
public void rainHard() throws RainedOut{} //基类的方法抛出了异常,而重写的方法不抛出也是能够的
public void event() {} //重写的方法抛出基类异常的子类也是能够的
public void atBat() throws PopFoul{} public static void main(String[] args) {
try{///以下的两句代码中构造器中可能抛出RainedOut,BaseballException异常
///atBat()方法可能抛出PopFoul异常.所以须要处理三种异常
StormyInning si = new StormyInning();
si.atBat();
}
catch(PopFoul e){
System.out.println("Pop Foul");
}
catch(RainedOut e){
System.out.println("Rained Out");
}
catch(BaseballException e){
System.out.println("Generic baseball");
}
try{//这段代码进行了向上转型,所以处理上面的三种情况外
///还必须处理基类atBat()方法抛出的Strike异常
Inning i = new StormyInning();
i.atBat();
}
catch(Strike e){
System.out.println("Strike");
}
catch(PopFoul e){
System.out.println("Pop Foul");
}
catch(RainedOut e){
System.out.println("Rained Out");
}
catch(BaseballException e){
System.out.println("Generic baseball");
}
}
}

Thinking in Java---异常处理机制的更多相关文章

  1. JAVA 异常处理机制

    主要讲述几点: 一.异常的简介 二.异常处理流程 三.运行时异常和非运行时异常 四.throws和throw关键字 一.异常简介 异常处理是在程序运行之中出现的情况,例如除数为零.异常类(Except ...

  2. Java 异常处理机制和集合框架

    一.实验目的 掌握面向对象程序设计技术 二.实验环境 1.微型计算机一台 2.WINDOWS操作系统,Java SDK,Eclipse开发环境 三.实验内容 1.Java异常处理机制涉及5个关键字:t ...

  3. java异常处理机制 (转载)

    java异常处理机制 本文来自:曹胜欢博客专栏.转载请注明出处:http://blog.csdn.net/csh624366188 异常处理是程序设计中一个非常重要的方面,也是程序设计的一大难点,从C ...

  4. Java异常处理机制 —— 深入理解与开发应用

    本文为原创博文,严禁转载,侵权必究! Java异常处理机制在日常开发中应用频繁,其最主要的不外乎几个关键字:try.catch.finally.throw.throws,以及各种各样的Exceptio ...

  5. 如何正确使用Java异常处理机制

    文章来源:leaforbook - 如何正确使用Java异常处理机制作者:士别三日 第一节 异常处理概述 第二节 Java异常处理类 2.1 Throwable 2.1.1 Throwable有五种构 ...

  6. 【转】深入理解java异常处理机制

    深入理解java异常处理机制 ; int c; for (int i = 2; i >= -2; i--) { c = b / i; System.out.println("i=&qu ...

  7. Java异常处理机制的秘密

    一.结论 这些结论你可能从未听说过,但其正确性是毋庸置疑的,不妨先看看: 1.catch中throw不一定能抛回到上一层,因为finally中的return会抑制这个throw 2.finally中t ...

  8. Java异常处理机制及两种异常的区别

    java异常处理机制主要依赖于try,catch,finally,throw,throws五个关键字.   try 关键字后紧跟一个花括号括起来的代码块,简称try块.同理:下面的也被称为相应的块. ...

  9. java异常处理机制详解

    java异常处理机制详解 程序很难做到完美,不免有各种各样的异常.比如程序本身有bug,比如程序打印时打印机没有纸了,比如内存不足.为了解决这些异常,我们需要知道异常发生的原因.对于一些常见的异常,我 ...

  10. Java异常处理机制 try-catch-finally 剖析

    Java拥有着强大的异常处理机制,最近初步学习了下,感觉内容还是挺多的,特此来将自己的理解写出来与大家分享. 一. 在Java代码code中,由于使用Myeclipse IDE,可以自动提醒用户哪里有 ...

随机推荐

  1. jira ao UpgradeTask

    插件发布到市场后,后续版本迭代的过程中,可能会对ao实体类的字段作添加或删除,或者要将某一字段的值映射解析到另一字段上. 本来这个工作,可以在插件启动的时候,在实现了com.atlassian.sal ...

  2. Ibatis.Net 表连接查询学习(五)

    IBatis.Net之多表查询 一.定制实际对应类的方式 首先配置多表的测试数据库,在之前Person表中增加一列"CountryId",新建一张Country表,两张表关系如下: ...

  3. 使用JS实现俄罗斯方块游戏

    简单的JS俄罗斯方块游戏源码 效果图: 代码如下,复制即可使用: <!DOCTYPE html> <html> <head> <meta charset=&q ...

  4. 织梦任意页面调用{dede:field.content/}的方法

    过滤掉所有的html代码,只显示文字,具体的ID自己更改. 代码如下: {dede:sql sql='Select content from dede_arctype where id=1'} [fi ...

  5. C语言——第零次作业

    A:你对网络专业或计算机专业了解是怎样? 据我所知计算机专业未来前景不错,不仅就业路子广,毕业工资高,而且在全世界都很吃香.但是,计算机专业是一个非常难学的专业,尽管人们追趋逐耆也没有填补计算机高端人 ...

  6. IDEA中Ctrl+Shift+F快捷键无效的解决方式

    某天突然发现idea非常重要的快捷键ctrl+shift+F无效了,网上搜了很多都说是qq快捷键冲突,但是找了下qq快捷键却没有解决,现在给大家一个解决快捷键冲突的思路: 1.查看QQ快捷键--> ...

  7. JavaScript中的普通函数与构造函数

    问题 什么是构造函数? 构造函数与普通函数区别是什么? 用new关键字的时候到底做了什么? 构造函数有返回值怎么办? 构造函数能当普通函数调用吗? 以下是我的一些理解,理解错误的地方恳请大家帮忙指正, ...

  8. Latex常用整理

    会不断更新添加,以便写论文的时候快速查找. 项目 带编号 \begin{enumerate} \setlength{\itemsep}{0pt} \setlength{\parsep}{0pt} \s ...

  9. CSS------让ul中高度不同的li底部对齐

    如图: 代码:(需要将li中vertical-align属性设置为bottom) <ul style="margin-top:50px"> <li style=& ...

  10. 【Vue实战之路】二、路由使用基础,六步搞定Vue-router

    vue-router的出现是为了解决路由与视图(实际项目中的单文件组件)的对应关系.若单单为了实现交互时对相应组件的渲染,则通过vue的基础操作完全可以实现,那么为什么要是用vue-router呢,个 ...