目录
一、RunTimeException和其他Exception
二、捕获异常
三、多重捕获块
四、throws/throw 关键字
1、throws关键字
2、throw关键字
3、throw关键字与throws关键字的区别
五、finally关键字
六、finally块和return
1、一个不容易理解的事实:在 try块中即便有return,break,continue等改变执行流的语句,finally也会执行。
2、finally中的return会抑制(消灭)前面try或者catch块中的异常
3、finally中throw的异常会覆盖(消灭)前面try或者catch中的异常
Throwable是Error和Exception的父类,用来定义所有可以作为异常被抛出来的类。
Error是编译时错误和系统错误,系统错误在除特殊情况下,都不需要你来关心,基本不会出现。而编译时错误,如果你使用了编译器,那么编译器会提示。
Exception则是可以被抛出的基本类型,我们需要主要关心的也是这个类。
Exception又分为RunTimeException和其他Exception。
使用 try 和 catch 关键字可以捕获异常。try/catch 代码块放在异常可能发生的地方。
try/catch代码块中的代码称为保护代码,使用 try/catch 的语法如下:
try
{
// 程序代码
}catch(ExceptionName e1)
{
//Catch 块
}
Catch 语句包含要捕获异常类型的声明。当保护代码块中发生一个异常时,try 后面的 catch 块就会被检查。
如果发生的异常包含在 catch 块中,异常会被传递到该 catch 块,这和传递一个参数到方法是一样。
下面的例子中声明有两个元素的一个数组,当代码试图访问数组的第四个元素的时候就会抛出一个异常。
// 文件名 : ExcepTest.java
import java.io.*;
public class ExcepTest{
public static void main(String args[]){
try{
int a[] = new int[2];
System.out.println("Access element three :" + a[3]);
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("Exception thrown :" + e);
}
System.out.println("Out of the block");
}
}
我们可以在编译器里面运行后可以看到运行结果
一个 try 代码块后面跟随多个 catch 代码块的情况就叫多重捕获。
多重捕获块的语法如下所示:
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}catch(异常类型3 异常的变量名3){
// 程序代码
}
上面的代码段包含了 3 个 catch块。
可以在 try 语句后面添加任意数量的 catch 块。
如果保护代码中发生异常,异常被抛给第一个 catch 块。
如果抛出异常的数据类型与 ExceptionType1 匹配,它在这里就会被捕获。
如果不匹配,它会被传递给第二个 catch 块。
如此,直到异常被捕获或者通过所有的 catch 块。
try {
file = new FileInputStream(fileName);
x = (byte) file.read();
} catch(FileNotFoundException f) { // Not valid!
f.printStackTrace();
return -1;
} catch(IOException i) {
i.printStackTrace();
return -1;
}
如果无法正常编译很正常,保护代码中的错误比较多。
throws关键字用在方法声明上,明确告诉调用者本方法可能产生的的异常,但方法本身不处理,用throws向上层抛出。
//throws关键字的简单使用
public class Test{
public static void main(String[] args) {
try{
System.out.println(print(10,0));
}catch (Exception e){//程序中出现错误的所有具体异常均是由Exception继承而来,e为Exception类的一个对象,该类对象由IVM产生,不需new就可直接使用
e.printStackTrace();
}
}
public static int print(int x,int y)throws Exception{//在方法声明上使用,但不做任何处理,将异常抛回上层
return x/y;
}
}
其他方法若想调用throws关键字声明的方法,在调用时必须使用try…catch进行异常捕获。因该方法可能出现异常,故必须按照异常方法进行处理。
public class ExcepTest{
public static void main(String[] args) {
try{
System.out.println(print(10,0));
}catch (Exception e){
e.printStackTrace();
}
fun();
}
public static int print(int x,int y)throws Exception{
return x/y;
}
public static void fun(){
try{
System.out.println(print(12,3));
}catch(Exception e){
e.printStackTrace();
}
}
}
一个方法可以声明抛出多个异常,多个异常之间用逗号隔开。
例如,下面的方法声明抛出 RemoteException 和 InsufficientFundsException:
import java.io.*;
public class className
{
public void withdraw(double amount) throws RemoteException,
InsufficientFundsException
{
// Method implementation
}
//Remainder of class definition
}
throw是直接编写在语句中,表示人为进行异常抛出。如果异常类对象实例化不希望由JVM产生而由用户产生,此时使用throw关键字来完成。
//throw关键字的简单使用
public class Test{
public static void main(String[] args){
try{
throw new Exception("你今天真好看!");
}catch (Exception e){
e.printStackTrace();
}
}
}
1.throw关键字用于方法内部,表示人为异常抛出。
2.throws关键字用于方法声明上,明确告诉用户本方法可能产生的异常,同时该方法可能不处理该异常。
finally 关键字用来创建在 try 代码块后面执行的代码块。
无论是否发生异常,finally 代码块中的代码总会被执行。
在 finally 代码块中,可以运行清理类型等收尾善后性质的语句。
finally 代码块出现在 catch 代码块最后,语法如下:
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}finally{
// 程序代码
}
public class ExcepTest{
public static void main(String args[]){
int a[] = new int[2];
try{
System.out.println("Access element three :" + a[3]);
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("Exception thrown :" + e);
}
finally{
a[0] = 6;
System.out.println("First element value: " +a[0]);
System.out.println("The finally statement is executed");
}
}
}
注意:在 try/catch 后面添加 finally 块并非强制性要求的
public class ExcepTest{
public static void main(String[] args){
int re = bar();
System.out.println(re);
}
private static int bar() {
try{
return 5;
} finally{
System.out.println("finally");
}
}
}
finally中的return 会覆盖 try 或者catch中的返回值。
class TestException {
public static void main(String[] args) {
int result;
try {
result = foo();
System.out.println(result); //输出100
} catch (Exception e) {
System.out.println(e.getMessage()); //没有捕获到异常
}
try {
result = bar();
System.out.println(result); //输出100
} catch (Exception e) {
System.out.println(e.getMessage()); //没有捕获到异常
}
}
//catch中的异常被抑制
@SuppressWarnings("finally")
public static int foo() throws Exception {
try {
int a = 5 / 0;
return 1;
} catch (ArithmeticException amExp) {
throw new Exception("我将被忽略,因为下面的finally中使用了return");
} finally {
return 100;
}
}
//try中的异常被抑制
//J2SE 提供的最后一个批注是 @SuppressWarnings。该批注的作用是给编译器一条指令,告诉它对被批注的代码元素内部的某些警告保持静默。
@SuppressWarnings("finally")
public static int bar() throws Exception {
try {
int a = 5 / 0;
return 1;
} finally {
return 100;
}
}
}
结果会是正常打印finally语句块中的两个"return 100"
public class TestException {
public static void main(String[] args) {
int result;
try {
result = foo();
} catch (Exception e) {
System.out.println(e.getMessage()); //输出:我是finaly中的Exception
}
try {
result = bar();
} catch (Exception e) {
System.out.println(e.getMessage()); //输出:我是finaly中的Exception
}
}
//catch中的异常被抑制
@SuppressWarnings("finally")
public static int foo() throws Exception {
try {
int a = 5 / 0;
return 1;
} catch (ArithmeticException amExp) {
throw new Exception("我将被忽略,因为下面的finally中抛出了新的异常");
} finally {
throw new Exception("我是finally中的Exception");
}
}
//try中的异常被抑制
@SuppressWarnings("finally")
public static int bar() throws Exception {
try {
int a = 5 / 0;
return 1;
} finally {
throw new Exception("我是finally中的Exception");
}
}
}
上面的3个例子都异于常人的编码思维,因此我建议:
不要在fianlly中使用return。
不要在finally中抛出异常。
减轻finally的任务,不要在finally中做一些其它的事情,finally块仅仅用来释放资源是最合适的。
将尽量将所有的return写在函数的最后面,而不是try ... catch ... finally中。