1、异常顶层父类~Throwable类
Throwable类是Java异常类型的顶层父类,Throwable又派生出Error类和Exception类。
错误:Error类 以及他的子类的实例,代表了JVM本身的错误。错误不能被程序员通过代码处理,Error很少出现。因此,程序员应该关注Exception为父类的分支下的各种异常类。
异常:Exception类 以及他的子类,代表程序运行时发送的各种不期望发生的事件。可以被Java异常处理机制使用,是异常处理的核心。
2、运行时异常、非运行时异常
根据Javac对异常的处理要求,将异常类分为2类。
非检查异常(unckecked exception)也叫运行时异常:即编译时不会产生异常,运行产生异常。Error 和 RuntimeException 以及他们的子类。。这样的异常发生的原因多半是代码写的有问题。如除0错误ArithmeticException,
错误的强制类型转换ClassCastException,数组索引越界ArrayIndexOutOfBoundsException,使用了空对象NullPointerException等等。
检查异常(checked exception)也叫非运行时异常:即不管你代码写的正确与否,你都要进行处理,因为JVM认为你这段代码产生的异常的概率大。本质:是因为你调用的那些方法在底层实现时就抛出了异常。。除了Error 和 RuntimeException的其它异常。javac强制要求程序员为这样的异常做预备处理工作(使用try…catch…finally或者throws)。
如SQLException , IOException,ClassNotFoundException 等。
3、异常处理语法
1.、对于检查异常,有2种不同的处理方式:使用try…catch…finally语句块处理它。或者,在函数签名中使用throws 声明交给函数调用者caller去解决。
2、注意点:
1、try块中的局部变量和catch块中的局部变量(包括异常变量),以及finally中的局部变量,他们之间不可共享使用。
2、 try块中存放放可能产生异常对象的代码,如果检测 try块中代码不产生异常,就不会执行catch块代码。否则,当try代码块产生异常对象时,会自动执行catch代码块,并且将异常对象传递给参数 e.
3、try{}代码块产生的异常一定要是catch中参数的 真正异常的类型 或者是其 子类
4、 每一个catch块用于处理一个异常。异常匹配是按照catch块的顺序从上往下寻找的,如果同一个try块下的多个catch异常类型有父子关系,异常子类 要放在 异常父类 的前面.
如果所有的catch都抓不住,可能就相当于我们没有处理到,又可能由JVM处理
5、finally块不管异常是否发生,只要对应的try执行了,则它一定也执行。只有一种方法让finally块不执行:System.exit()。
因此finally块通常用来做资源释放操作:关闭文件,关闭数据库连接等等。良好的编程习惯是:在try块中打开资源,在finally块中清理释放这些资源。
6、 try{}catch{} , try{} finally{} , try{}catch{}finally{} 这三种写法是正确的。
4、获取异常信息的方法
Throwable父类中 常用的三个方法 用来获得对象中的异常描述信息
try{ System.out.println(10/0); }catch (ArithmeticException e) { // e.printStackTrace(); //打印异常对象 堆栈详细信息 , System.out.println(e.getMessage()); //获取错误信息 System.out.println(e.toString()); //返回此 throwable 的简短描述 } / by zero java.lang.ArithmeticException: / by zero
5、常见的异常类
public static void main(String[] args) { //多重异常捕获(多重catch块):对产生的异常对象逐个去进行匹配,直到匹配成功为止 //注意 异常子类 要放在 异常父类 的前面 try { Integer a = new Integer("aa你好"); } catch (NullPointerException e) { System.out.println("空指针异常"); } catch (ArithmeticException e) { System.out.println("算术异常"); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("数组索引越界异常"); } catch (ClassCastException e) { System.out.println("类型转换异常"); } catch(NumberFormatException e){ System.out.println("数字格式异常"); } catch (Exception e) { System.out.println("你是个异常,我就能治好你"); } finally{ System.out.println("只要执行了try块,我总会执行"); } System.out.println("end"); } 结果: 数字格式异常 只要执行了try块,我总会执行 end
6、自定义异常
如果要自定义异常类,则扩展Exception类即可,因此这样的自定义异常都属于检查异常(checked exception)。如果要自定义非检查异常,则扩展自RuntimeException。
throw、throws的区别
throw 用来创建异常对象,在方法里面, 后面只能够跟一个具体的异常对象
throws 用来申明我这个方法中的某段代码有异常。 在方法签名后面,即在() {}之间, 后面跟多个异常类型
package cm.异常处理; /* 自定义异常的流程 :下面是第一步: * ① 自定义一个类 * ② 继承 Exception 或者 RuntimeException * ③ 提供一个公共无参数的构造方法和一个String参数的构造方法 */ public class MuException extends Exception { private static final long serialVersionUID = 1L; public MuException() { super(); } public MuException(String message) { super(message); } }
package cm.异常处理; /* * 第二步: 设计一个注册Register的方法,根据条件判断在适当的时候抛出(产生)一个上面1的异常对象,抛出去。 */ public class Register { private static String[] users = { "小王", "小李", "小明" };// 写一个数组,模拟已经注册的用户 //注册用户名的方法 public static void register(String userName) throws MuException{ for(int i=0;i<users.length;i++){ // 条件判断,如果用户名不为空,且已经存在,则抛出一个MultipleException异常 if(userName!="" && userName.equals(users[i])){ // throw:在方法里向调用者抛出异常 throw new MuException("亲,用户名:" + userName + "已经注册,请重新输入!"); } } //没有重复,则注册成功 System.out.println("恭喜你,注册成功!玩的开心!!"); } }
package cm.异常处理; public class TestRegister { public static void main(String[] args) { try{ Register.register("哈哈"); }catch(MuException e){ e.printStackTrace(); } try{ Register.register("小王"); }catch(MuException e){ e.printStackTrace(); } } } 结果; 恭喜你,注册成功!玩的开心!! cm.异常处理.MuException: 亲,用户名:小王已经注册,请重新输入! at cm.异常处理.Register.register(Register.java:13) at cm.异常处理.TestRegister.main(TestRegister.java:14)