异常处理
异常
指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。
在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象。Java处理异常的方式是中断处理。
异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行.
异常体系
- java.lang.Throwable
- error
- Error:代表的系统级别错误(属于严重问题)系统一旦出现问题,sun公司会把这些错误封装成Error对象,Error是给sun公司自用的,不是给我们程序员用的;因此我们开发人员不用管它。
- Exception:异常,代表程序可能出现的问题;我们通常会用Exception以及他的子类来封装程序出现的问题
- RuntiomeException【runtime异常】
- 运行时异常: RuntimeException本身和子类;编译阶段不报错,是程序运行时出现的;
- 编译时异常(其他异常)【checked异常】:除了RuntimeExcpetion和他的子类
- :没有继承RuntimeExcpetion的异常,直接继承于Excpetion。编译阶段就会错误提示;作用在于提醒程序员。
- 在编译时期,就会检查,如果没有处理异常,则编译失败。(如日期格式化异常)
- RuntiomeException【runtime异常】
- error
Java文件.java --javac命令(编译时异常)--> 字节码文件.class --java命令(运行时异常)--> 运行结果
编译阶段java不会运行代码,只会检查语法是否错误,或者做一些性能优化:
int a = 2.2; // 语法错误
String s = "a"+"b"+"c"; //性能优化"abc"
出现异常,不要紧张,把异常的简单类名,拷贝到API中去查。
异常作用
- 异常是用来查询bug的关键参考信息
- 异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况
public void setAge(int age){
if(age < 18){
throw new RuntimeException();
}else{
this.age = age;
}
}

获取异常信息
Throwable 的成员方法:
| 方法名称 | 说明 |
|---|---|
| public string getMessage() | 返回此 throwable 的详细消息字符串;获取异常的描述信息,原因(提示给用户的时候,就提示错误原因。 |
| public String toString() | 返回此可抛出的简短描述;获取异常的类型和异常描述信息 |
| public void printstackTrace() | 把异常的错误信息输出在控制台(仅仅是打印);打印异常的跟踪栈信息并输出到控制台。 |
正常的输出语句
System.out.println(123);
错误的输出语句(用来打印错误信息)(红色)
多线程的知识,和sout一起执行输出顺序随机
System.err.println(123);
public class demo1 {
public static void main(String[] args) {
int[] arr ={1,2,3,4,5};
try{
System.out.println(arr[10]);
}catch(ArrayIndexOutOfBoundsException e){
//e.getMessage();
//e.toString();
e.printStackTrace();
//仅仅是打印,不会停止程序运行
//包含e.getMessage();和e.toString();还有异常的位置
//Index 10 out of bounds for length 5
}
System.err.println("111");//111
}
}
处理方式
-
jvm虚拟机默认处理异常
-
捕获异常:不让程序停止
-
抛出异常thorws:写在方法定义处,表示声明一个异常:告诉调用者,使用本方法可能会有哪些异常
编译时异常: 必须要写。运行时异常: 可以不写。
public void 方法() throws 异常类名1,异常类名2,...{}thorw:写在方法内,结束方法;手动抛出异常对象,交给调用者;方法中下面的代码不再执行了
public void 方法(){ throws new 异常类名(); } -
public class Demo { public static void main(String[] args) { try { read("a.txt"); } catch (FileNotFoundException e) { //抓取到的是编译期异常 抛出去的是运行期 throw new RuntimeException(e); } finally { System.out.println("不管程序怎样,这里都将会被执行。"); } System.out.println("over"); } -
public static void read(String path) throws FileNotFoundException { if (!path.equals("a.txt")) {//如果不是 a.txt这个文件 // 我假设 如果不是 a.txt 认为 该文件不存在 是一个错误 也就是异常 throw throw new FileNotFoundException("文件不存在"); } } -
finally:当只有在try或者catch中调用退出JVM的相关方法,此时finally才不会执行,否则finally永远会执行。
-
在编写程序时,我们必须要考虑程序出现问题的情况。这时需要使用抛出异常的方式来告诉调用者。
抛出异常throw使用格式
//throw new 异常类名(参数); throw new NullPointerException("要访问的arr数组不存在"); throw new ArrayIndexOutOfBoundsException("该索引在数组中不存在,已超出范围");如果产生了问题,我们就会throw将问题描述类即异常进行抛出,也就是将问题返回给该方法的调用者。
那么对于调用者来说,该怎么处理呢?一种是进行捕获处理,另一种就问题声明出去,使用throws声明处理。
将问题标识出来,报告给调用者。如果方法内通过throw抛出了编译时异常,而没有捕获处理,那么必须通过throws进行声明,让调用者去处理。
关键字throws运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常).
声明异常格式:
修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{ }声明异常的代码演示:
public class ThrowsDemo { public static void main(String[] args) throws FileNotFoundException { read("a.txt"); } // 如果定义功能时有问题发生需要报告给调用者。可以通过在方法上使用throws关键字进行声明 public static void read(String path) throws FileNotFoundException { if (!path.equals("a.txt")) {//如果不是 a.txt这个文件 // 我假设 如果不是 a.txt 认为 该文件不存在 是一个错误 也就是异常 throw throw new FileNotFoundException("文件不存在"); } } }throws用于进行异常类的声明,若该方法可能有多种异常情况产生,那么在throws后面可以写多个异常类,用逗号隔开。
public class ThrowsDemo2 { public static void main(String[] args) throws IOException { read("a.txt"); } public static void read(String path)throws FileNotFoundException, IOException { if (!path.equals("a.txt")) {//如果不是 a.txt这个文件 // 我假设 如果不是 a.txt 认为 该文件不存在 是一个错误 也就是异常 throw throw new FileNotFoundException("文件不存在"); } if (!path.equals("b.txt")) { throw new IOException(); } } }
-
-
抛出异常:告诉调用者出错了
-
在方法中,出现异常了,方法就没有继续运行下去的意义了,采取抛出处理。让该方法结束运行并告诉调用者出现了问题;然后调用者捕获try...catch
-
throws
- 写在方法定义处,表示声明一个异常,告诉调用者使用本方法可能出现哪些异常
- 编译时异常必须要写,运行时异常可以不写
-
throw
- 写在方法里,结束方法,手动抛出异常交给调用者,下面的方法不用执行了
-
当代码出现异常时,可以让程序继续往下执行。
try{ //可能出现异常的代码; sout:arr[10] //此处出现了异常,程序就会在这里创建一个ArravIndex0utofBoundsException对象 //new ArravIndexOutofBoundsException(); //拿着这个对象到catch的小括号中对比,看括号中的变量是否可以接收这个对象 //如果能被接收,就表示该异常就被捕获(抓住) ,执行catch里面对应的代码/ //当catch里面所有的代码执行完毕,继续执行try...catch体系下面的其他代码 }catch(异常的类型 ArrayIndexOutOfBoundsException 变量名 e){ //异常的处理代码; //记录日志/打印异常信息/继续抛出异常 sout:"索引越界" } sout:"继续执行"如果try中没有遇到问题;会把try里面所有的代码全部执行完毕,不会执行catch里面的代码;只有当出现了异常才会执行catch里面的代码
如果try中可能会遇到多个问题,可以写多个catch对应;只写一个catch,加入碰到第一个异常直接进入catch,后续的异常执行不到
如果我们要捕获多个异常,这些异常中如果存在父子关系的话,那么父类一定要写在下面
JDK7以后:
catch(ArrayIndexOutOfBoundsException | ArithmeticException e){}如果try中遇到的问题没有被捕获,相当于try...catch的代码白写了,最终还是会交给虚拟机进行处理。
如果try中遇到了问题,下面的代码就不会执行了,直接跳转到对应的catch当中,执行catch里面的语句体但是如果没有对应catch与之匹配,那么还是会交给虚拟机进行处理
-
public class People {
private int age;
public People(int age) {this.age = age;}
public People() {}
public int getAge() {return age;}
public void setAge(int age)throws RuntimeException{
if(age<18 || age >25){
throw new RuntimeException();
}
this.age = age;
}
}
public class demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
People p = new People();
while(true){
try{
System.out.println("输入年龄");
String ageStr = sc.nextLine();
int age = Integer.parseInt(ageStr);
p.setAge(age);
break;
}catch (NumberFormatException e){
System.out.println("年龄格式有误");
}catch(RuntimeException e){
System.out.println("范围有误");
}
}
System.out.println(p);
}
}
异常注意事项
- 运行时异常被抛出可以不处理。即不捕获也不声明抛出。
- 如果父类抛出了多个异常,子类覆盖父类方法时,只能抛出相同的异常或者是他的子集。
- 父类方法没有抛出异常,子类覆盖父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出
- 当多异常处理时,捕获处理,前边的类不能是后边类的父类
- 在try/catch后可以追加finally代码块,其中的代码一定会被执行,通常用于资源回收。
自定义异常
在开发中根据自己业务的异常情况来定义异常类.
- 运行时异常表示由于参数错误导致的异常;继承于
java.lang.RuntimeException。 - 编译时异常提成程序员检查本机信息如数据库等;继承于
java.lang.Exception。
自定义一个业务逻辑异常: LoginException。一个登陆异常类。
要求:我们模拟登陆操作,如果用户名已存在,则抛出异常并提示:亲,该用户名已经被注册。
public class LoginException extends Exception {
//空参构造
public LoginException() {}
//带参异常
public LoginException(String message) {
super(message);//表示异常提示
}
}
public class Demo {
// 模拟数据库中已存在账号
private static String[] names = {"bill","hill","jill"};
public static void main(String[] args) {
//调用方法
try{
// 可能出现异常的代码
checkUsername("nill");
System.out.println("注册成功");//如果没有异常就是注册成功
} catch(LoginException e) {
//处理异常
e.printStackTrace();
}
}
//判断当前注册账号是否存在
//因为是编译期异常,又想调用者去处理 所以声明该异常
public static boolean checkUsername(String uname) throws LoginException {
for (String name : names) {
if(name.equals(uname)){//如果名字在这里面 就抛出登陆异常
throw new LoginException("亲"+name+"已经被注册了!");
}
}
return true;
}
}

浙公网安备 33010602011771号