三种异常类型
- 检查性异常:最具代表的检查异常时用户错误或问题引起的异常,这是程序员无法预见的,例如要打开一个不存在的文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
- 运行时异常:运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
- 错误ERROR:错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
Throwable(异常的超类)
-
ERROR(错误)
- VirtulMachineError(虚拟机异常)
- StackOverFlowError
- OutOfMemoryError
- AWTError(GUI编程图形界面化异常)
- VirtulMachineError(虚拟机异常)
-
Exception(异常)
- IOException(IO异常)
- EOFException
- FileNotFoundException
- RuntimeException(运行时异常)
- ArrithmeticException(算数异常)
- MissingResourceException(丢失资源)
- ClassNotFoundException(找不到类)
- NullPointerException(空指针异常)
- IllegalArgumentException
- ArrayIndexOutOfBoundsException(数组下标越界异常)
- UnkownTypeException(未知的类型异常)
- IOException(IO异常)
Error与Exception区别
Error通常时灾难性的致命错误,时程序无法控制和处理的,当出现这些异常时,Java虚拟机(JVM)一般会选择终止线程;Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常。
异常处理机制
-
抛出异常
-
捕获异常
-
异常处理五个关键字:
- try、catch、finally、throw、throws
捕获异常 try…catch
捕获异常:Java中对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式处理。
捕获异常语法如下:
try:该代码块中编写可能产生异常的代码。
catch:用来进行某种异常的捕获,实现对捕获到的异常进行处理。
注意:try和catch都不能单独使用,必须连用。
Finally 块
有一些特定的代码无论异常是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些语句执行不到,而finally就是解决这个问题的,在finally代码块中存放的代码都是一定会被执行的。
什么时候的代码必须最终执行?
当我们在try语句块中打开了一些物理资源(如 IO流、网络、数据库链接等),都需在使用完之后,最终关闭打开的资源。
finally 的语法: try…catch…finally:自身需要处理异常,最终还得关闭资源。
注意:finally 不能单独使用。
package com.exception;
public class Test {
public static void main(String[] args) {
int a=1;
int b=0;
//快捷键 ctrl+alt+t
System.out.println(a/b);
//要捕获多个异常:从小到大!
try {//try监控区域
new Test().a(); //可能出现异常的代码
}catch (ArithmeticException e){//catch(想要捕获的异常类型!) 捕获异常
System.out.println("程序出现异常,变量b不能为0" );//处理异常的代码 记录日记 打印异常信息 继续抛出异常
}catch (Error e){
System.out.println("Error");
}catch (Exception e){
System.out.println("Exception ");
} finally {//处理善后工作
System.out.println("finally");
}
//finally 可以不要finally 假设IO,资源,关闭!
}
public void a(){
b();
}
public void b(){
a();
}
}
抛出异常 throw
在Java中,提供一个throw关键字,它用来抛出一个指定的异常对象。
- 创建一个异常对象。封装一些提示信息(信息可以自己编写)
- 需要将这个异常对象告知调用者。通过关键字throw将这个异常对象传递到调用者处。throw用在方法内,用来抛出一个异常对象,将使用格式: throw new 异常类名(参数—你想告知用户的异常信息);
注意:如果产生了问题,我们通过throw将异常进行抛出,也就是将问题返回给该方法的调用者。那么调用者该怎么处理那?一种是进行捕获处理,另一种就是继续将问题生命出去,使用throws声明处理。
声明异常 throws
将问题标识出来,报告给调用者。如果方法内通过throw抛出了 编译时异常,而没有捕获处理,那么必须通过throws 进行声明,让调用者去处理。关键字 throws 运用于方法声明上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常)。
声明异常语法: 修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{}
throws 用于进行异常的声明,若该方法可能有多种异常情况产生,那么在 throws 后面可以写多个异常类,用逗号隔开。最大的异常习惯放后面。
异常处理两种方式
如果异常出现的话,会立刻终止程序,所以我们得处理异常:
- 声明异常:throws该方法不处理,而是声明可能出现的异常,将问题暴露给调用者,让调用者自己处理!
- 捕获异常:try catch 在方法中使用try-catch的语句块直接处理可能出现的异常!
package com.exception;
public class Test2 {
public static void main(String[] args) {
try {
new Test2().test(1,0);
}catch(ArithmeticException e){
e.printStackTrace();
}
}
//假设这方法中,处理不了这个异常。方法上抛出异常
public void test(int a,int b){
if(b==0){//throw throws
throw new ArithmeticException();//主动的抛出异常,一般在方法中使用
}
}
}
异常注意事项
多个一擦汗给你使用捕获又该如何处理?
- 多个异常分别处理。
- 多个异常一次捕获,多次处理。
- 多个异常一次捕获一次处理。
一般我们使用一次捕获多次处理的方法,格式如下:
try{
//可能出现异常的代码
}catch(异常类型A e){//当 try 中出现A类型异常,就用该catch来捕获
//处理异常的代码
//记录日记/打印异常信息/继续抛出异常
}catch(异常类型B e){//当 try 中出现B类型异常,就用该catch来捕获
//处理异常的代码
//记录日记/打印异常信息/继续抛出异常
}
注意:这种处理方式,要求多个catch中的异常不相同,并且若catch中的多个异常之间有子夫类异常的关系,那么子类异常要求在上面的catch处理,父类异常在下面的catch处理。
- 运行时异常被抛出可以不处理,即不捕获也不声明抛出。
- 如果finally有return语句,永远返回finally中的结果,避免该情况。
- 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。
- 父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出。(throws)
自定义异常
在开发中根据自己业务的异常情况来定义异常类:
例如 自定义一个业务逻辑异常:PasswordErrorException。密码错误类。
异常类如何自定义:
- 自定义一个检查异常:自定义类 并继承于 java.lang.Exception
- 自定义一个运行时期的异常类:自定义类 并继承于 java.lang.RuntimeException
public static void main(String[] args) {
UserService ser =new UserService();
try {
//异常可以处理,也可以不处理:运行时异常
boolean res1=ser.validateName("test1");
System.out.println(res1);
} catch (UserNameIsNotExistException e) {
e.printStackTrace();
}
try {
//必须处理异常:有可能是检查异常
boolean res=ser.login("teset1","teset");
System.out.println(res);
} catch (UserPwdErrorException e) {
e.printStackTrace();
}
}
public class UserService {
public boolean validateName(String name) {
if(!name.equals("test")) {
throw new UserNameIsNotExistException();
}else {
return true;
}
}
public boolean login(String name,String pwd) throws UserPwdErrorException{
if(name.equals(pwd)) {
return true;
}else {
throw new UserPwdErrorException();
}
}
}
public class UserNameIsNotExistException extends RuntimeException{
public UserNameIsNotExistException() {
super("用户名不存在!");
}
}
public class UserPwdErrorException extends Exception{
public UserPwdErrorException() {
super("用户名或密码错误!");
}
}