李屁屁不才,肚子里面的墨水就这么多了,如有错误,欢迎指正,虽是原创,也有参考了别人文章地方。
Throwable(可抛出)是Java程序中所有错误的父类。
两个重要的子类:Exception(异常)和 Error(错误)
Exception(异常)分两类,RuntimeException运行时异常和其他异常,比如IOException,SQLException等。
一、首先了解两个关键字,throw和throws
throw在函数类使用,出现某种不希望出现的情况后,便throw一个异常对象,比如,你不希望int x为一个奇数
if ( x %2 ) throw new Exception();
像这样抛出一个合适的异常对象就可以了,可以是自定义的异常类的对象
throws在函数上使用,在方法体内,可能抛出了某种异常,但是却并没有在函数内部对异常进行处理
public void f ( ) throws Exception
方法需要告诉调用者,可能会出现的异常类型
虽然说在catch块对异常进行匹配的时候,会默认使用instanceof关键字,但是catch块能够捕捉到的异常类型必须能够将明的异常类型包括在内
比如:
throws Exception,一旦try,就至少要有catch(Exception e)
throws IOException,RuntimeException,一旦try,就至少要有catch (IOException e)
二、异常抛出的最上层
异常一般都是两种处理方法,一种在异常出现的方法内部,try-catch,将异常处理,然后继续处理try-catch-finally代码块之后的代码,另外一种就是throws向上抛出,抛给方法的调用者,方法的调用者处理异常的方法也是只有这两种。
那如果一直一直向上抛出,抛到哪里才会停止呢!
多线程:
最终由Thread.run()抛出,线程退出
单线程:
最终由main()主方法抛出,程序退出
三、RuntimeException 运行时异常
这是一类比较特殊的异常
首先,RuntimeException 系统自动检查范围内的可以不用throw
比如:c=a/b,当b==0的,此处系统自动会抛出一个ArithmeticException异常
然后,一般方法中没有处理的异常,都要在函数上使用throws声明抛给方法的调用者,RuntimeException 可以省略throws语句
RuntimeException 异常如果在方法体中没有处理,IVM虚拟机会自动接管该异常,默认地向上抛出,就和写好了throws语句一样
简单说,JVM虚拟机会自动接管RuntimeException 异常,遇到匹配的catch语句,同样执行处理操作,没有被处理,JVM会隐式地向上抛出,不需要throws声明语句。
注意一点,RuntimeException 是Exception 的子类,所以会被catch(Exception e)给捕捉到。
当我们懒得写throws语句一级一级将异常抛出的时候,我们可以让我们自定义的异常继承RuntimeException ,这样可以节省代码,但是不能清楚知道异常到底在拿个地方被处理了。
四、fianlly
不管是一直向上抛出异常到最上层,线程退出,或者是程序退出,还是在try或者catch块中遇到return语句,finally中的代码块都会被执行。
我们只需要记住只有以下四种情况,finally才不执行:
1)在finally语句块中发生了异常。
2)在前面的代码中用了System.exit()退出程序。
3)程序所在的线程死亡。
4)关闭CPU。
五、try-catch-finally语法
最常见的try-catch-finally就不多说啦
try-catch没有finally是可以的,但是try中一旦出现异常,之后的代码块是不会执行的,finally是为了弥补这一点
try-finally怎么解释呢,RuntimeException 是可以被虚拟机接管的,现在不想处理,就交给虚拟机好啦,反正也不用修改多少代码,但是如果只有一个try块,与不写try块又有啥区别,所以如果没有catch块,finally块还是必须的。
import java.io.IOException;
class MyException extends Exception
{
public MyException(String s)
{
super(s);
System.out.println("defined a MyException extends Exception");
}
public String toString()
{
return "MyException";
}
}
class MyException1 extends RuntimeException
{
public MyException1(String s)
{
super(s);
System.out.println("defined a MyException1 extends RuntimeException");
}
public String toString()
{
return "MyException1";
}
}
class MyException2 extends IOException
{
public MyException2(String s)
{
super(s);
System.out.println("defined a MyException2 extends Exception");
}
public String toString()
{
return "MyException2";
}
}
public class TestException {
public TestException()
{
System.out.println("Create a Test");
}
public void test(int i)throws Exception //即使声明只是父类Exception,但是catch的时候会自动用到instanceof这个关键字
{
int x=i;
if(x<=-2){
throw new MyException("it is illegal!because i<=-2.");
}
if(x==0){
throw new MyException1("a kind of RuntimeException!because i==0.");
}
if(x>=2){
throw new MyException2("it is also illegal!because i>=2.");
}
System.out.println("i="+x);
}
public void test1(int i)//throws Exception,运行时异常会自动交给JVM虚拟机接管,所以可以不throws声明异常
{
int x=i;
//if(x<=-2){
// throw new MyException("it is illegal!because i<=-2.");
//}
if(x==0){
throw new MyException1("a kind of RuntimeException!because i==0.");
}
//if(x>=2){
// throw new MyException2("it is also illegal!because i>=2.");
//}
System.out.println("i="+x);
}
public void test2(int i)throws IOException //在内部不处理,显式地往上抛出,由此方法的调用者处理,处理非运行时异常的两种方法之一
{
int x=i;
//if(x<=-2){
// throw new MyException("it is illegal!because i<=-2.");
//}
if(x==0){
throw new MyException1("a kind of RuntimeException!because i==0.");
}
if(x>=2){
throw new MyException2("it is also illegal!because i>=2.");
}
System.out.println("i="+x);
}
public void test3(int i)//throws Exception,在方法内部就对非运行时异常处理,处理非运行时异常的两种方法之一
{
int x=i;
//if(x<=-2){
// throw new MyException("it is illegal!because i<=-2.");
//}
//if(x==0){
// throw new MyException1("a kind of RuntimeException!because i==0.");
//}
try
{
if(x>=2){
throw new MyException2("it is also illegal!because i>=2.");
}
}
catch(Exception e)
{
System.out.println(e.getMessage()); //和构造函数里面的super()有关
System.out.println(e); //默认调用toString()方法
}
finally
{
System.out.println("i="+x+"in fianlly!");
}
System.out.println("i="+x);
}
public static void main(String[] args)
{
TestException te=new TestException();
for(int i=-2;i<3;) //捕获异常的时候的顺序特别重要,因为按顺序匹配,只要有一个catch块执行后,就不再执行接下来的catch块了
try {
te.test(i++);
}
catch (RuntimeException e) {
System.out.println(e.getMessage());
System.out.println(e);
e.printStackTrace(); //虚拟机默认的异常处理方法
//就是main()主方法(最上层)抛出了异常差不多,但是这里程序还能继续执行,main()抛出异常程序就会退出了,这大概就是异常处理的意义了吧
}catch (IOException e){
System.out.println(e.getMessage());
System.out.println(e);
e.printStackTrace();
}
catch (Exception e){
System.out.println("Exception");
System.out.println(e.getMessage());
System.out.println(e);
e.printStackTrace();
}
try
{
te.test2(0); //这里只能捕捉到IOException,捕捉不到运行时异常,虚拟机会继续把运行时异常往上抛出,给到main主方法,于是程序退出
}
catch(IOException e)
{
System.out.println(e.getMessage());
System.out.println(e);
e.printStackTrace();
}
finally{
System.out.println("Finally!");
}
//te.test2(2); //这里会抛出IOException异常,可是没有try—catch处理语句,方法的调用者main函数也没有声明异常,所以会报错
te.test1(1);
te.test1(0);
}
}
写的时候参考了以下几篇文章,感谢作者
1.http://blog.csdn.net/hguisu/article/details/6155636
2.http://blog.csdn.net/lxlzhn/article/details/4484872
3.http://takeme.iteye.com/blog/1842644