`

Java中的异常

阅读更多

关键字:

Throwable,

Exception,

Error,

Runtime Exception,

unChecked Exception,

Checked Exception,

throw,

throws,

try,

catch,

finally

 

我们先看看类图:

 

 

首先你需要明白,这些都是类,是对象,就和其它的对象没有两样,你可以为它定义方法,当然,这些方法的目的是为捕获异常而提供额外的信息,这也是我们使用异常的目的。特别是Throwable,我以前一直以为这是一个接口。

 

Throwable

正如这个类的名字所蕴含的意思一样,是一个可被抛出的对象,这个对象定义了一个可以被抛出对象应该是什么样的,即,一个错误或者异常应该具备的基本信息。

Error

错误一般是被虚拟机保留用于表示资源不足,或者是其它的一些使得程序无法继续执行下去的错误发生时候,被虚拟机所抛出来的。这是一个惯例,所以你最好不要自己去实现新的Error子类。如果你要抛出一个Error也是可以的,但是不建议这样做,因为这个约定俗成是让系统来抛出,如果想要抛出一个异常来中断程序,你可以抛出runtime exception。

Exception

异常,包括了受检的异常checked exception和运行时异常runtime exception

受检的异常比如IOException,使用它的目的是当异常发生时候,期望调用者能够适当地对异常进行恢复。比如你在读写一个文件,这时候需要catch IOException,当然这个时候如果出现了IOException,被你捕获到了,那么你可以对这个异常进行处理,比如提示用户,让用户重新测试等等,避免了程序崩溃。

运行时异常用在程序出现了错误的情况下,比如NullPointerException。这种异常和Error,一旦发生就不能被捕获,或者说捕获也没有意义,因为它直接就会导致程序的奔溃,不可恢复。

因此运行时异常runtime exceptionError都被称为unChecked Exception--未受检异常。

 

 

我们来对上面的关系进行下梳理:

首先,java语言提供了3中可抛出结构(throwable):checked exception,runtime exception,error。

throwable是他们的父类,定义了一个异常最基本的结构,error是系统级别的错误,有可能是你的程序导致的,但你不需要过多去理会,当然,继承这个类实现一个自己的Error也没有多大的意义,它和runtime exception有个共同的地方就是:一旦发生就无法恢复,直接导致程序奔溃,因此他们被称为unchecked exception。而checked exception是用来当异常发生的时候,让程序避免奔溃而采取的做法。当你认为程序可以允许恢复,那你使用checked exception,比如IOException,否则使用runtime exception,比如空指针异常NullPointerException。在不清楚到底该使用哪个的情况下,最好使用unchecked exception.

 

 

分析完上面的关系后,我们看看,该如何抛出和处理一个异常呢?

 

throw关键字是用来在java中抛出异常使用的,如下:

 

抛出运行时异常:(会导致程序崩溃)

 

public void setAge(int age) {
		
		if(age < 0)
		{
			throw new RuntimeException("Sorry ,the age of person can not be a negative number");
		}
		this.age = age;
	}

 

 

抛出错误:(会导致程序崩溃,不建议使用)

 

public void setAge(int age) {
		if(age < 0)
		{
			throw new Error("Sorry ,the age of person can not be a negative number");
		}
		this.age = age;
	}

 

抛出checked exception(不会导致程序奔溃,在当前方法中处理异常):

 

public void setAge(int age) {
		
		if(age < 0)
		{
			
			try {
				throw new Exception("Sorry ,the age of person can not be a negative number");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		this.age = age;
	}
 

 

抛出checked exception(不会导致程序奔溃,将异常抛出给调用这个方法的地方进行处理):

 

public void setAge(int age) throws Exception{
		
		if(age < 0)
		{
			throw new Exception("Sorry ,the age of person can not be a negative number");
		}
		this.age = age;
	}
 

 

对应的,我们在调用这个方法的时候,需要这样做:

 

try {
					person.setAge(-1);
				} catch (Exception e) {
					// 这里不要让处理异常的地方空着,这样就算捕获到了异常也没有意义了,
					// 如果你认为这个地方可以不做任何处理,至少需要包含一条提示,说明下为什么不做处理。方便以后调试,或者供别人参考
					Log.e(TAG, "You shoud check the value of name before pass it to the method");
					showExceptionTip();//对错误进行处理
					e.printStackTrace();
				}

 或者你也可以这样处理:假如这个调用者,自己也会被别人调用,那么也可以不处理这个方法,也通过Throws Exception将异常抛出去。交给外部调用者来处理,就好像是,我不知道该如何处理这个问题,就把他交给上级来处理。

 

 

 

注意:当你catch到异常的时候,并不是不做处理,这样就算捕获到了异常也没有意义了,如果你认为这个地方可以不做任何处理,至少需要包含一条提示,说明下为什么不做处理。方便以后调试,或者供别人参考。

 

前面我们说的,抛出runtime exception,error,checked exception.还有一种情况是这样的:

抛出throwable,即,它们的父类

 

public void setAge(int age){
		
		if(age < 0)
		{
			try {
				throw new Throwable("Sorry ,the age of person can not be a negative number");
			} catch (Throwable e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		this.age = age;
	}

 或:

 

public void setAge(int age) throws Throwable{
		if(age < 0){
			throw new Throwable("Sorry ,the age of person can not be a negative number");
		}
		this.age = age;
	}

 这种做法虽然可以,但是是不可取的,为什么呢?但是你会发现,由于Throwable是Error和Exception的父类,如果发生错误了,你甚至都不知道这个错误是Error还是Exception,这肯定不是我们使用异常处理想达到的目的。

 

 

看完上面的代码块现在说明下我们所用到的关键字:

 

throw,throws

 

throw表示将这个异常抛出去,它可以抛出unchecked exception(runtime exception,error),checked exception,throwable.即,可以抛出Throwable对象及其之类,由于unchecked exception如果发生了,直接导致程序奔溃,因此就没有将异常交给外部来处理这个概念了,而对于checked exception来说,它的目的是对程序发生的异常就行处理,避免程序奔溃,因此,总是需要对发生的异常进行处理,至于在哪里处理,这个你可以灵活选择,如果你不想在本方法中进行处理,你可以选择在外部进行处理,即,调用这个方法的地方进行处理,这个时候你就需要使用throws关键字,将它抛出去了。当然正如我前面所说的,这个异常还可以再被抛出去,一级一级递归上去,直到你希望它在哪个地方进行处理。

 

具体处理异常的时候,我们使用的是try catch,关键字

这个不做解释,大家都懂,需要注意的是,try块应该尽量的小,这样方便你捕获异常。

 

 

最后我们讲一讲finally关键字,finally不是每次调用try catch的时候都需要调用它来对资源进行清理,使用它的目的是:对一些消耗内存的对象进行释放,比如数据库连接对象JDBC啊,等等。注意:释放的时候先要判断是对象是否为null。

 

下面是开发过程中常见的错误汇总:

 

1.丢弃异常,即如我前所说的,捕获到了异常却不做处理,那捕获了又有什么意义呢?

2.不指定具体的异常,其实我这里为了演示的方便,也没有指定具体的异常,实际开发中应该指定具体的异常,这样方便调试,还有一点是,如果你捕获多个异常的时候,即同时catch多个具体异常时候,需要从小到大,不能将Exception放在第一个,这样你永远都不会捕获到具体的异常,等于下面的具体异常都是dead code

3.异常捕获后没有对大的资源进行释放,这时候我们就需要使用finally

4.try块过于庞大,这样很不利于调试。

 

 

下面是针对上面的代码块调试过程中对Logcat的各种截图:

 

unchecked exception:运行时异常RuntimeException:

 

unchecked exception:Error:不推荐这样做,约定俗成Error是给系统用的

 

checked exception:

 

checked exception:带有Log说明的,这样做方便找出问题,毕竟e.printStackTrace();打印出的有效信息不多,自己定义说明,有利于调试

 

抛出throwable:不推荐这样的做法,因为实在不利于调试

 

 

 

下面是代码块所在的工程,有兴趣的同学可以去下载来看看:

 

https://github.com/michaelye/ExceptionDemo

 

 

  • 大小: 8.4 KB
  • 大小: 25.5 KB
  • 大小: 23.2 KB
  • 大小: 16.8 KB
  • 大小: 23.5 KB
  • 大小: 16.6 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics