java异常
java异常
概述:程序在运行过程中出现的不正常现象或配置中产生的问题,不经过处理的异常将终止程序运行(开发过程中出现的语法错误和逻辑错误不是异常,语法错了,编译不通过,不会产生字节码文件,根本不能运行)。
在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象。目的是帮助我们找到程序中的问题
,Java处理异常的方式是中断处理。
异常处理
java编程语言使用异常处理机制为程序提供异常处理能力
Throwable
所有错误和异常的父类
异常的体系结构
-
Error:JVM、硬件、执行逻辑错误,不能手动处理
如:StackOverflowError----------栈溢出错误
-
Exception:程序在运行和配置中产生的问题
- RuntimeException:运行时异常,可处理可不处理
- CheckedException:检查(编译)时异常,编译异常,必须处理
注意:Exception除了RuntimeException及其子类外的所有子类都是检查时异常
类型 | 说明 |
---|---|
NullPointerException | 空指针异常 |
ArrayIndexOutBoundsException | 数组越界异常 |
ClassCastException | 类型转换异常 |
NumberFormatException | 数字格式化异常 |
ArithmeticException | 算术异常 |
Throwable成员方法
常用方法名 | 描述 |
---|---|
public String getMessage() | 返回此 throwable 的详细消息字符串 |
public String toString() | 返回此可抛出的简短描述 |
public void printStackTrace() | 把异常的错误信息输出在控制台 |
public class ExceptionDemo02 {
public static void main(String[] args) {
System.out.println("开始");
method();
System.out.println("结束");
}
public static void method() {
try {
int[] arr = {1, 2, 3};
System.out.println(arr[3]); //new ArrayIndexOutOfBoundsException();
System.out.println("这里能够访问到吗");
} catch (ArrayIndexOutOfBoundsException e) { //new ArrayIndexOutOfBoundsException();
// e.printStackTrace();
//public String getMessage():返回此 throwable 的详细消息字符串
// System.out.println(e.getMessage());
//Index 3 out of bounds for length 3
//public String toString():返回此可抛出的简短描述
// System.out.println(e.toString());
//java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
//public void printStackTrace():把异常的错误信息输出在控制台
e.printStackTrace();
// java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
// at com.itheima_02.ExceptionDemo02.method(ExceptionDemo02.java:18)
// at com.itheima_02.ExceptionDemo02.main(ExceptionDemo02.java:11)
}
}
}
程序执行产生异常的过程
异常产生的原因
- 当程序在运行时遇到不符合规范的代码或结果时,会产生异常,可使用
throws
关键字手动抛出异常- 注意:
throws
关键字并没有真正处理异常,只是将异常抛给了调用者,即谁调用可能存在异常的成员,谁就处理该异常,若一直上抛直至main方法后,main方法仍不处理,则最终会由JVM进行处理,当我们对一个可能存在运行异常的代码不做任何处理时,系统会隐式默认使用throws
关键字将异常抛给Exception,最终由JVM做默认处理,处理方式有如下两个步骤:
- 把异常的名称,错误原因及异常出现的位置等信息输出在了控制台
- 程序停止执行,所以最后才会输出异常信息并中断程序
- 但是,如果是编译时异常,则没有默认处理方式,因为编译时异常时一定要显式处理的,所以没必要拥有默认处理方式
异常的传递
按照方法的调用链反向传递,如果始终没有处理异常,最终会有JVM进行默认的异常处理(打印堆栈跟踪信息)
public class TestException {
/**
* 异常的传递:按照方法的调用链反向传递,如果始终没有处理异常,最终会有JVM
* 进行默认的异常处理(打印堆栈跟踪信息),例子:
* main方法调用operation方法,operation方法调用show方法,当show方法出现异
* 常而没有进行处理时,jvm会把未处理的异常反向抛给operation方法,operation
* 方法也没有处理时,抛给mian方法,main方法还没有处理异常,jvm会进行默认的异常处
* 理:打印堆栈跟踪信息
* Exception in thread "main" java.lang.ArithmeticException: / by zero
* at com.company.TestException.show(TestException.java:24)
* at com.company.TestException.operation(TestException.java:15)
* at com.company.TestException.main(TestException.java:11)
* @param args
*/
public static void main(String[] args) {
operation();
}
static void operation() {
show();
}
static void show() {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个数字:");
int i = sc.nextInt();
System.out.println("请再输入一个数字:");
int j = sc.nextInt();
int a = i / j;
System.out.println(a);
}
}
Java的异常处理关键字
- try:执行可能产生异常的代码,在发生异常的语句处直接跳到catch语句块,try语句块中异常语句后面的代码不再执行,如果没有异常,则不会跳转到catch语句块
- catch:捕获并处理异常
- finally:无论有无异常都执行此代码,除非退出JVM,它可以释放资源,根据需要可写可不写
- throws:手动向上抛出异常,异常并未处理,谁调用谁处理
- throw:声明方法一定有异常抛出,通常搭配try…catch或throws关键字使用,运行时异常可以不处理,检查时异常必须处理
try…catch方式处理异常
/**
* Java的异常处理关键字:
* try:执行可能产生异常的代码
* catch:捕获并处理异常
* finally:无论有无异常都执行此代码,用来释放资源,除非退出java虚拟机
* throws:手动抛出异常
* throw:声明方法可能要抛出的异常
*/
public class TestException {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入被除数:");
int i = sc.nextInt();
System.out.println("请输入除数:");
int j = sc.nextInt();
int consult;//商
/**
* try{
* 执行可能产生异常的代码
* }catch(异常类型 引用名){
* 异常处理语句
* }finally{
* 必定执行的代码,用来释放资源,除非退出java虚拟机,只有在try或者catch中调用退出JVM的相关方法(比如System.exit(0)),此时finally才不会执行,否则finally永远会执行。
* }
*/
try{
consult = i / j;//除数不能为0,若为0,报算术异常:ArithmeticException
// 当发生异常时,在异常语句处直接跳到catch语句块中,try语句块中后面的语句不执行
System.out.println(i + " / " + j + " = " + consult);//不执行
}catch(Exception e){//这里可以写异常的父类,也可以写具体的子类,但是一定要
// 保证是该类型的异常,不然会出现异常不匹配
e.printStackTrace();//输出异常的堆栈信息
}finally {
System.out.println("总是有我!");
}
}
}
- 执行流程
- 程序从 try 里面的代码开始执行
- 出现异常,就会跳转到对应的 catch 里面去执行
- 执行完毕之后,程序还可以继续往下执行
多重catch
public class TestException {
public static void main(String[] args) {
/**
* try{
* 执行可能产生异常的代码
* }catch(异常类型 引用名){
* 异常处理语句
* }catch(异常类型 引用名){
* 异常处理语句
* }catch(异常类型 引用名){
* 异常处理语句
* }finally{
* 必定执行的代码
* }
* (1)发生异常时,从前往后按顺序逐个匹配
* (2)只执行第一个匹配的异常处理语句
* (3)子类异常在前,父类异常在后
* 注意:在多重catch的异常处理中,父类的异常处理语句必须放在所有
* 异常处理语句的后面,否则将会报异常已被捕获错误
*/
try {
Scanner sc = new Scanner(System.in);
System.out.println("请输入被除数:");
int i = sc.nextInt();
System.out.println("请输入除数:");
int j = sc.nextInt();
int consult;//商
consult = i / j;
System.out.println(i + " / " + j + " = " + consult);
} catch (InputMismatchException e) {
System.out.println("输入类型不匹配异常,只能输入数字!!!");
} catch (ArithmeticException e) {
System.out.println("算术异常,除数不能为0!!!");
} catch (Exception e) {
System.out.println("我是所有异常的父类!");
} finally {
System.out.println("我可以释放资源!");
}
}
}
![]() | ![]() | ![]() |
throws:向上抛出异常
概述:定义功能方法时,需要把出现的异常暴露出来让调用者去处理,就通过throws在方法上声明。
throws后面可以跟多个异常类名,用逗号隔开。尽量不要在main方法上抛出异常。
public class TestException {
/**
* 对于被调用者上抛的异常,可以使用try{}catch(){}语句进行异常处理,也
* 可以使用throws关键字继续把异常往上抛,如果最终没有对异常进行处理,
* 会默认交给JVM处理,JVM会打印异常的堆栈信息,程序将被打断
*/
public static void main(String[] args) throws Exception {
show();
/**
* try{
* show();
* }catch(Exception e){
* e.printStackTrace();
* }
*/
}
static void show() throws Exception{
/**
*此段代码可能存在异常,但是这里先不处理,使用throws关键字抛出异常,
* 将异常抛给上一级,就是把异常抛给它的调用者,这里是main方法
*/
Scanner sc = new Scanner(System.in);
System.out.println("请输入被除数:");
int i = sc.nextInt();
System.out.println("请输入除数:");
int j = sc.nextInt();
int consult;//商
consult = i / j;
System.out.println(i + " / " + j + " = " + consult);
}
}
throw:手动抛出异常
概述:在功能方法内部出现的某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。
手动抛出异常,通常搭配try…catch或throws关键字使用,运行时异常可以不处理,检查时异常必须处理
public class TestException {
public static void main(String[] args) throws Exception {
show();
}
static void show() throws Exception {
Scanner sc = new Scanner(System.in);
System.out.println("请输入被除数:");
int i = sc.nextInt();
System.out.println("请输入除数:");
int j = sc.nextInt();
int consult;//商
consult = i / j;
System.out.println(i + " / " + j + " = " + consult);
/**
* throw new 异常类型(提示):手动抛出一个异常,告诉别人这里有个异常,这个
* 异常如果是运行时异常可以不处理,如果是检查时异常必须处理,否则编译不能通
* 过,可以使用throws关键字往上抛,也可以用try{}catch(){}语句进行处理
*/
throw new Exception("这里会出现算术异常");
}
}
- 带有异常声明的方法覆盖:
- 方法名、参数列表、返回值类型必须与父类相同
- 子类的访问修饰符范围大于等于父类
- 子类中的方法,不能抛出比父类更多、范围更广的检查时异常
异常注意事项
-
多个异常使用捕获又该如何处理呢?
- 多个异常分别处理。
- 多个异常一次捕获,多次处理。
- 多个异常一次捕获一次处理。
一般我们是使用一次捕获多次处理方式,格式如下:
try{
//编写可能会出现异常的代码
}catch(异常类型A e){ //当try中出现A类型异常,就用该catch来捕获.
//处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}catch(异常类型B e){ //当try中出现B类型异常,就用该catch来捕获.
//处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}
- 注意:这种异常处理方式,要求多个catch中的异常不能相同,并且若catch中的多个异常之间有继承关系,那么子类异常必须写在父类异常前面,平级关系的异常没有先后顺序的要求。
- 注意:
try里面的代码越少越好。
catch里面必须有内容,至少要给出一个简单的提示信息。- 一旦try里面出现了异常,JVM就会实例化这个异常,并将这个异常对象抛出,如果和catch语句里的异常类相匹配,就会执行相应的catch里面的处理,然后结束try…catch语句,继续执行后面的代码。
- 可以明确的异常尽量明确,不要用父类来处理,以便提高运行的效率。
- 运行时异常被抛出可以不处理。即不捕获也不声明抛出。
- 如果finally有return语句,永远返回finally中的结果,应避免在finally中写return的情况.
- 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。
- 父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出
throws与throw的区别
throws | throw |
---|---|
用在方法声明后面,跟的是异常类型 | 用在方法体重,跟的是异常对象 |
表示抛出异常,由该方法的调用者来处理 | 表示抛出异常,由方法体内的语句处理 |
表示出现异常的一种可能,并不一定会发生这些异常 | 执行throw一定抛出了某种异常 |
final,finally和finalize的区别:
1)final:表示最终的,可以修饰类、成员变量和成员方法
修饰类,类不能被继承
修饰成员变量,变量是常量
修饰成员方法,方法不能被重写
2)finally:是异常处理的一部分,用来释放资源
一般来说,finally后面的代码一定会执行
特殊情况:在执行到finally之前JVM退出了
3)finalize:Object类里面的一个方法,用于垃圾回收
注意:
如果catch里面有return语句,fianlly里面的代码会在return语句之前执行。确切地说,应该在中间执行。
程序执行到return语句时会形成返回路径,如果后面还有finally语句,就继续执行finally里面的代码,再次回到以前的返回路径,返回以前的返回值