·为什么会有异常机制:
a) 异常处理机制可以让产生异常的语句抛出异常,然后处理异常,并且程序接着往下执行不需要中断执行。
b) 有时候无法穷举所有异常情况,就用异常机制。
·Java异常被分为runtime异常,和checked异常。只要不是继承RuntimeException类的类型异常都属于Checked异常。
·异常处理机制:
a): 当某条语句有异常时候会抛出一个Exception类型的对象来通知程序。
b): checked异常必须处理否则无法通过编译,runtime异常无需处理。异常处理方法有2种:
一、使用try{}catch{} finally{} 语句处理异常,这个语句就是专门处理异常的。
二、不处理异常就使用throws抛出异常。这个语句是不处理异常,但是调用这个方法的那个方法处理,如果它还不处理那么它也需要抛出去,最终的方法是main方法,如果还没有处理,那么main方法它就抛给jvm处理,jvm就会将错误打印出来我们就可以看到。
总结:总之不处理异常就的把它抛给别人。
c): 对于runtime异常,无需使用try..catch..finally处理,也不需要使用throws显示的抛出,它会自动抛出这个异常信息并停止运行。
·异常类的继承关系:
·Error和Exception都继承于Throwalble,Error是jvm出错,比如崩溃等,Error也是不会被捕获到的。
·异常捕获语法:
try
{
可能会产生异常的语句。
}
catch(类型 变量) //这里传进来对于类型的对象才会执行,否则不执行。
{
处理异常。
} //多个catch块
finally
{
清理工作。无论无何finally块中的语句,都会被执行。
}
·throw语句语法:
throw 对象;
·throws语句语法:
方法(方法签名) throws 异常类型a,异常类型b,异常类型n
说明:
a): catch块可以有多个,catch块有传进来类型的对象才会执行,否则不执行,当有异常类型对象传递进来时,会从上到下遍历catch中声明的类型,直到找到一个匹配的对象后则进入该块执行该块中的语句,所以catch多个块中也只有一个块会被执行。catch块中声明的异常类型必须是从小到大的否则编译错误。finally块可有可无,catch块也可以没有但是没有catch块就没有意义了。
b): throw 是程序员自己让程序抛出一个异常类型的对象。抛出的对象要么处理要么继续使用throws抛出。
c): throws 是放在方法签名后面,作用是如果方法中使用了throw抛出了异常对象。抛出多个异常使用逗号隔开异常类型,并且如果子类重写父类方法,那么子类抛出的这个异常类型要比父类这个方法跑出异常的类型范围要小。
例子:
public class DivTest { public static void main(String[] args) { try{ //哪条语句可能出现异常,就把哪条语句写到这里面,不出现异常的语句不需要写到try块中。 int[] i = new int[2]; i[0] = 1; i[1] = 2; i[2] = 3; //这里数组越界,所以这句会抛出一个异常对象,对象类型是IndexOutOfBoundsException类型的 //测试输出try执行流程:但没有执行到这里,说明try{}块执行过程中遇到一行抛出异常对象的代码后,那么try{}块就跳到catch块中了,try{}块抛出异常代码下面的所有代码都不会得打执行了。从这个地方到try{}块结束的位置这些代码如果不抛出异常,那么就不要写到这里了,写到try{}块外面就好。看Testa.java的改写 System.out.println("test output1"); for(int a : i) { System.out.println(a); } System.out.println("test output!"); } catch(ArithmeticException ae) { System.out.println("arithmetic exception"); } catch(IndexOutOfBoundsException ioobe) //所以这里接受上面异常抛出的对象,然后进行处理这就是catch块的作用。 { //System.out.println(ioobe.getMessage()); //ioobe.printStackTrace(); System.out.println("OutOfBounds"); } catch(Exception e) { System.out.println("I don't no"); } finally //不管try{}块抛不抛出异常,finally都会得到执行,这里进行清理工作,比如说对try{}块中打开的物理资源进行回收。物理资源:打开一个文件,一个网络或数据库连结等等的。 { System.out.println("I like Dog"); } //这里可以执行 System.out.println("ok"); } } //总结:try{}块里的程序,某句话抛出了异常对象,则从该句语句这里跳出try{}块,跳到了对应的catch块(try{}块抛出异常对象所属类型的catch块),执行完catch块后再接着执行其他代码。 //如果程序执行完try{}块中的内容后没有抛出异常对象,那么catch块就接收不到对应类型的对象了,那么它就不会执行了,接着执行下面其他代码。 ++++++++++++++++++++++++改写代码+++++++++++++++++++++++++++ public class Testa { public static void main(String[] args) { int[] i = null; try { i = new int[2]; i[0] = 1; i[1] = 2; // i[2] = 3; } catch(ArithmeticException ae) { System.out.println("arithmetic exception"); } catch(IndexOutOfBoundsException ioobe) { //System.out.println(ioobe.getMessage()); //ioobe.printStackTrace(); System.out.println("OutOfBounds"); } catch(Exception e) { System.out.println("I don't no"); } finally { System.out.println("exec finally"); } System.out.println("test output1"); for(int a : i) { System.out.println(a); } System.out.println("test output!"); System.out.println("exec tail"); } }
·访问异常信息:
·所有异常对象都包含了以下几个常用方法:
a): getMessage()返回此 throwable 的详细消息字符串.
b) : printStackTrace 将此 throwable 及其追踪输出至标准错误流。此方法将此 Throwable
对象的堆栈跟踪输出至错误输出流,作为字段System.err
的值。
c) : printStackTrace(PrintStream s) 将此 throwable 及其追踪输出到指定的输出流。
d): getStackTrace()提供编程访问由 printStackTrace()
输出的堆栈跟踪信息
例子:
将Testa例子的注释去掉,输出结果就是下面这样
另类的例子实际中并不用到:
public class FinallyFlowTest { public static void main(String[] args) throws Exception //main方法中的语句可能会抛出异常 { boolean a = FinallyFlowTest.test(); System.out.println(a); } public static boolean test() { try { System.out.println("exec try"); // 因为finally块中包含了return语句 // 所以下面的return语句失去作用 return true; //System.exit(1); //这条语句跟return根本就不同,这就相当于你打开一个浏览器并且打开了很多页面,return相当于关掉一个页面,而System.exit()则相当于关闭浏览器。而整个JVM就相当于是这个浏览器。 //System.out.println("这下面的都不会执行了"); //这里去掉开头的注释就出现语法错误,因为return下面的语句到不到执行,try块中就会报错。 } finally { //return false; System.out.println("exec finally"); } } } -------------------------------------------------------- 例子:main方法中不使用try..catch..final处理异常,使用throws抛给jvm -------------------------------------------- import java.io.*; public class ThrowsTest { public static void main(String[] args) throws IOException { // try // { FileInputStream f = new FileInputStream("a.txt"); // } // catch(IOException io) // { // System.out.println(io.getMessage()); // io.printStackTrace(); // } } }
输出结果:
去掉注释的输出结果:
清楚的知道了getMessage()输出的结果就是printstackTrace()方法中包含的说明信息。
·自定义异常类
·通常自定义异常类都是直接继承Exception类的一个类。如果希望自定义Runtime异常类,则继承RuntimeException类。
·自定义异常类需要定义两个构造器,一个不带参数的构造器,一个带String类型的信息的构造器,带信息的构造器作为异常对象的描述信息(也就是getMessage()方法获取到的信息,也是printStackTrace()方法中显示的部分描述信息)。
例子:自定义异常类
public class MyException2 extends Exception { public MyException2() { //super(); //子类构造器中,如果不显示的使用super()调用父类带参数的构造器,那么它将隐式的调用父类不带参数的构造器。所以这里super()可以不写。 } public MyException2(String message) { super(message); //这里接受的message字符串就是作为异常对象的描述信息,这里是经过多步骤的操作的。 } +++++++++++++++ 上面就是自定义异常类,下面调用自定义异常类 +++++++++++++++++ public class ExceptionTest4 { public void method(String str) throws Exception //这里没有使用try..catch..finally处理,使用throws抛出Exception类型的throw生成的异常对象 { if(null == str) { throw new MyException("传入的字符串参数不能为null"); //这里就是throw抛出的异常的用法,可以使用try..catch..finally处理,也可以不处理,不处理就需要抛出 } else if("hello".equals(str)) { throw new MyException2("传入的字符串不能为hello"); } else { System.out.println(str); } } public static void main(String[] args) { try { ExceptionTest4 test = new ExceptionTest4(); test.method(null); //这里调用method方法,该方法抛出了异常,在这里处理method方法跑出的这个异常,所以它写到了try块中。 } catch(MyException e) { System.out.println("进入到MyException catch块"); e.printStackTrace(); } catch(MyException2 e) { System.out.println("进入到MyException2 catch块"); e.printStackTrace(); } catch(Exception e) { System.out.println("进入到Exception catch块"); e.printStackTrace(); } finally { System.out.println("异常处理完毕"); } System.out.println("程序执行完毕"); } }
输出结果:
上面少些一个自定义异常类,其实自定义异常类都是那个写法,一模一样。
-----------------------------------------------------------------------
最后说几句:
·根据printStackTrace()方法返回的结果,可以看到程序中所有异常抛出的线路图。
·能用正常逻辑判断解决的问题就轻易的解决掉,不要轻易使用异常,如果真的发生不可预料的异常情况才是使用异常的场合。