1、异常顶层父类~Throwable类
Throwable类是Java异常类型的顶层父类,Throwable又派生出Error类和Exception类。
代表了JVM本身的错误。错误不能被程序员通过代码处理,Error很少出现。因此,程序员应该关注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 用来创建异常对象,在方法里面, 后面只能够跟一个具体的异常对象
在方法签名后面,即在() {}之间, 后面跟多个异常类型
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)