抛出了无数的Exception,但是Exception到底是啥?解开Exception的神秘面纱...

java异常

什么是异常呢?

定义:当一个程序在运行过程中,出现了一些非正常执行流程的指令,那么就会产生一个事件对象,这个事件对象在java就简称为异常(Exception)。

An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program‘s instructions.

异常Handler:

当一个异常出现了,那么jvm就会去寻找一个Handler来处理这个异常。

下面树jvm调用过程以及Handler的调用过程,从图中可以看出,Handler过程是反序的。

异常的分类:

异常主要分为三类:

Error,代表这个异常非常致命,不需要被异常Handler捕获。

Checked Exception:受检异常,代表异常属于符合用户预期的异常,通常情况下,用户会采取相应的措施,尝试从异常中恢复,需要被异常Handler捕获。

Runtime Exception:运行时异常,通常是一个bug,一般用于表示该异常是用户没有预料到的,不需要被异常Handler捕获。

语法结构:

try语法结构:

try {

code

}

catch and finally blocks . . .

catch语法结构:

try {

} catch (ExceptionType name) {

} catch (ExceptionType name) {

}

finally语法结构:

try{

}catch(ExceptionType name){

}finally {

}

直接在方法中抛出并且捕获异常的结构:

public void method1() throws ExceptionType{

}

直接在方法中抛出异常

public void method1(){

if(index < 0){

throw new EmptyStackException();

}

}

异常的作用:

先看一个方法,使用的是伪代码...

readFile {
    open the file;
    determine its size;
    allocate that much memory;
    read the file into memory;
    close the file;
}

在这个方法中,我们会执行如下几个步骤

1打开文件

2查看文件大小

3开辟内存空间

4读取文件内容到内存中

5关闭文件

但是如果这个方法出现如下问题

1文件不可打开

2文件大小不可预知

3内存空间不够了

4如果读取文件失败了

5关闭文件失败了

如果不适用异常来处理这些异常,那么代码会是怎样子呢?

errorCodeType readFile {
    initialize errorCode = 0;

    open the file;
    if (theFileIsOpen) {
        determine the length of the file;
        if (gotTheFileLength) {
            allocate that much memory;
            if (gotEnoughMemory) {
                read the file into memory;
                if (readFailed) {
                    errorCode = -1;
                }
            } else {
                errorCode = -2;
            }
        } else {
            errorCode = -3;
        }
        close the file;
        if (theFileDidntClose && errorCode == 0) {
            errorCode = -4;
        } else {
            errorCode = errorCode and -4;
        }
    } else {
        errorCode = -5;
    }
    return errorCode;
}

每次客户端调用这个方法,都需要判断返回的状态码,从而来决定下一步来做什么...比如:

int status = readFile();
switch(status){
case -1: do something...
case -2: do someting...
}

这种代码是会让你发疯的,特别是一段时间之后,你再回来看这些代码,你会发现可读性特别差,如果在readFile()中再添加一些新的状态码,那么客户端的代码需要跟着一起

改变,这会给维护带来毁灭性的的工作,并且很容易引入新的bug。

下面是使用异常之后的代码:

readFile {
    try {
        open the file;
        determine its size;
        allocate that much memory;
        read the file into memory;
        close the file;
    } catch (fileOpenFailed) {
       doSomething;
    } catch (sizeDeterminationFailed) {
        doSomething;
    } catch (memoryAllocationFailed) {
        doSomething;
    } catch (readFailed) {
        doSomething;
    } catch (fileCloseFailed) {
        doSomething;
    }
}

通过异常,我们可以让代码的可读性更加完整,并且如果新增加异常,也不会改动客户端的代码。

我们再来看看另外一个列子

method1 {
    call method2;
}

method2 {
    call method3;
}

method3 {
    call readFile;
}

这是一个方法调用栈,方法method1() call method2() call method()3 call readFile()

如果没用异常处理机制,那么每个方法都会被强制进行错误诊断,那可是相当麻烦的,如下代码:

method1 {
    errorCodeType error;
    error = call method2;
    if (error)
        doErrorProcessing;
    else
        proceed;
}

errorCodeType method2 {
    errorCodeType error;
    error = call method3;
    if (error)
        return error;
    else
        proceed;
}

errorCodeType method3 {
    errorCodeType error;
    error = call readFile;
    if (error)
        return error;
    else
        proceed;
}

好吧,看完之后,你会被很多无关代码弄得心烦意乱了,各种乱...

下面我们使用异常来处理:

method1 {
    try {
        call method2;
    } catch (exception e) {
        doErrorProcessing;
    }
}

method2 throws exception {
    call method3;
}

method3 throws exception {
    call readFile;
}

我们仅仅在只关心的方法中处理异常...瞬间世界美好了。

另外,异常可以帮助我们将一些错误进行分类处理。比如在java.io中,需要各种各种的IO错误,比如打开文件失败,访问文件失败,关闭输出流失败等,我们都可以将这些异常归结为IOException,从更加高的层次去看待问题。

自定义异常:

通常情况下,如果你在开发一个工具包,出现了异常,那么用户可以直接自定义异常。异常的自定义非常简单,通常类名就表示错误类别。如:IllegalArgumentException,IOException,NegativeIndexException,FileNotFoundException等...但是有一点需要注意的是,选择继承的异常类很重要。如果错误是不可预知的,属于bug的,可以继承RuntionException,要么继承Exception吧。

总结:异常给了程序更加高的灵活性,并且让代码更加通熟易懂。所以正确使用异常,是非常重要的。在捕获异常时,应该是做到具体的异常类型,很多人懒惰,就直接在每个方法中throws Exception...可以这会给调试bug带来极大的困难。比如说异常是在一个10个方法堆栈中抛出的,那么异常链就会非常的大,想要定位到错误的所在地是困难的。同样,也不能随意的捕获异常甚至是将异常丢掉了,如下代码try{}catch(Exception){ignore...}。程序明明出现了错误,但是控制台啥也没有输出,这绝对是一个大坑。所以捕获异常的情况一般是:能处理异常,那么就可以捕获异常,如果不行,那么就抛出异常,丢给调用者来决定异常的处理情况。

时间: 2024-10-09 04:24:38

抛出了无数的Exception,但是Exception到底是啥?解开Exception的神秘面纱...的相关文章

Dubbo抛出自定义异常

最近开始学习Dubbo框架,在工作中会把之前的业务迁移过来. 在原来的Spring MVC框架实现中,有使用到自定义异常的场景(自定义异常继承RuntimeException).而对于异常(包括自定义异常),在业务代码中都不做任何try-catch操作,而是由公用的Controller来处理异常. 在使用dubbo的过程中,在dubbo的service端定义有自定义异常进行throw的时候,却发现在customer的Controller中无法instanceof,自己自定义的异常类被转成了Run

More Effective C++ 条款12 了解”抛出一个exception&quot;与“传递一个参数”或“调用一个虚函数”之间的差异

1. 函数return值与try块throw exception.函数接收参数与catch字句捕获异常相当类似(不仅声明形式相像,函数参数与exception传递方式都有三种:by value,by reference , ). 2. 尽管函数调用与异常抛出相当类似,“从抛出端传递一个exception到catch子句”和“从函数调用端传递一个实参到被调函数参数”仍然大有不同: 1)调用一个函数,控制权会最终回到调用端(除非函数失败以致无法返回),但是抛出一个exception,控制权不会再回到

java异常处理:建立exception包,建立Bank类,类中有变量double balance表示存款,Bank类的构造方法能增加存款,Bank类中有取款的发方法withDrawal(double dAmount),当取款的数额大于存款时,抛出InsufficientFundsException,取款数额为负数,抛出NagativeFundsException,如new Bank(100),

建立exception包,建立Bank类,类中有变量double  balance表示存款,Bank类的构造方法能增加存款,Bank类中有取款的发方法withDrawal(double dAmount),当取款的数额大于存款时,抛出InsufficientFundsException,取款数额为负数,抛出NagativeFundsException,如new Bank(100),表示存入银行100元,当用方法withdrawal(150),withdrawal(-15)时会抛出自定义异常. pa

PLSQL_Oracle Exception异常分类、异常抛出、异常处理、异常传播(概念)

2014-06-03 BaoXinjian 一.摘要 在PLSQL程序开发过程中,很重要的部分就是对程序异常的监控和处理,包括如何触发异常,何时进行处理,如何进行处理,是否将程式中的所有异常集中在一起,通过公共异常处理的procedure或function,如果没有完善的程式处理机制,很难说该程式是一只健壮的程式,当程式遇到很多类型或者量很多资料时,系统若没有异常处理必然会导致程式的出错 当预判到了某些异常,需要对预判到的异常进行合适相应的处理,是否抛出异常还是忽略还是其他 当然程式没有预判到或

2.建立exception包,建立Bank类,类中有变量double balance表示存款,Bank类的构造方法能增加存款,Bank类中有取款的发方法withDrawal(double dAmount),当取款的数额大于存款时,抛出InsufficientFundsException,取款数额为负数,抛出NagativeFundsException,

public class Bank { Double qian=0.0; double newBank(double a) { qian=qian+a; return qian; } double withDrawal(double dAmount) throws Exception { if(dAmount>qian) { throw new Exception("InsufficientFundsException"); } if(dAmount<0) { throw

抛出多个异常

java编程思想这本书上的一道练习题,题目是:定义三种新的异常类型,写一个类,在一个方法中抛出三种异常,在main中调用这个方法,仅用一个catch捕获三个异常 public class CatchMultiException {     public static void main(String[] args) throws Exception {         try {             test(2);         } catch (Exception e) {      

Dbcp2抛出org.apache.commons.dbcp2.LifetimeExceededException

1 三月 24, 2016 5:16:33 下午 org.apache.commons.dbcp2.BasicDataSource onSwallowException 2 警告: An internal object pool swallowed an Exception. 3 org.apache.commons.dbcp2.LifetimeExceededException: The lifetime of the connection [14] milliseconds exceeds

黑马程序员——————&gt; 异常处理之抛出

------- android培训.java培训.期待与您交流! ---------- java的异常被分类为两大类,Checked异常和Runtime异常(运行时异常).所有的RuntimeException类及其子类的实例被称为Runtime异常:不是RuntimeException类及其子类的异常实例则被称为Checked异常. 对于Checked异常的处理方式有如下两种. 1:当前方法明确知道如何处理该异常,程序应该使用try...catch块来捕获该异常,然后在对应的catch块中修复

捕获Java线程池执行任务抛出的异常

Java中线程执行的任务接口java.lang.Runnable 要求不抛出Checked异常, public interface Runnable { public abstract void run();} 那么如果 run() 方法中抛出了RuntimeException,将会怎么处理了? 通常java.lang.Thread对象运行设置一个默认的异常处理方法: java.lang.Thread.setDefaultUncaughtExceptionHandler(UncaughtExce