
16-异常处理
16-异常处理
一、异常概念
-
异常是程序在执行时发生的事件,它会打断指令的正常流程。
Java中提供了一种独特的处理异常的机制,通过异常来处理程序设计中出现的错误。
-
Java异常是一个描述在代码段中发生的异常情况(出错)的对象。
异常的产生
- 引发异常:
在Java程序的执行过程中,如果出现了异常事件,就会生成一个异常对象。生成的异常对象将传递给Java运行时系统,这一异常的产生和提交过程称为引发异常
- JRE(系统)产生异常对象
- 人为产生异常对象(明确用throw关键字)
异常有的是因为用户错误引起,有的是程序错误引起的,还有其它一些是因为物理错误引起的。
但并不是所有的错误都是异常,并且错误有时候是可以避免的。
比如,代码少了一个分号,那么运行出来结果是提示是错误 java.lang.Error;
如果用System.out.println(100/0),因为你用0做了除数,则会抛出 java.lang.ArithmeticException 的异常。
异常的分类
- 异常的根类(throwable)
- 错误:Error(程序无法处理的错误)
- 异常:Exception(可以处理的错误。程序可以捕获并处理这些异常事件)
Exception的分类
-
RunTimeException(运时期间异常)
-
RunTimeException的异常在程序中可以捕获,也可以不捕获处理。
-
非RunTimeException(编译期间的异常)
-
非RunTimeException的异常必须进行捕获,否则程序无法进行正常编译。
-
异常的大致分类可以看作
- 用户输入了非法数据。
- 要打开的文件不存在。
- 网络通信时连接中断,或者JVM内存溢出。
二、异常处理
当异常产生时,如果异常没有处理的话,这个异常将直接抛给虚拟机处理。虚拟机无法处理的话,程序就直接退出。
处理异常
//方式一:代码块中进行捕获
try{
//需要监听的代码块
}
catch (异常类型 异常名称/e ) {
//对捕获到try监听到的出错的代码块进行处理
throw 异常名称/e; //thorw表示抛出异常
throw new 异常类型(“自定义”);
}
finally{
//finally块里的语句不管异常是否出现,都会被执行
}
//方式二:声明方法时进行抓获
//throws只是用来声明异常,是否抛出由方法调用者决定
修饰符 返回值 方法名 () throws 异常类型{
//代码块
}
public class ExceptionTest {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
try{ //监听代码块
int a=input.nextInt();
int b=input.nextInt();
double sum=a/b;
// 尝试执行此代码,若代码出现异常对象,则跳转到catch块中
// 当try块中的代码出错之后,try块中剩余的所有语句不执行,程序跳转到catch块中
System.out.println(sum);
}
// try之后可以跟多个catch块
// catch块顺序:捕获多个异常对象时,若存在父子关系的,子类排前,父类排后,否则随便
catch(InputMismatchException e){ //catch(异常类型 异常名称)
System.out.println("只能输入数字");
throw e; //抛出catch捕捉到的异常
//throw new InputMismatchException(); 同上
}
catch(ArithmeticException e){
System.out.println("分母不能为0");
throw new ArithmeticException("分母为0抛出异常"); //抛出ArithmeticException异常
}
catch(Exception e){ //Exception是所有异常的父类
System.out.println("发生了其他异常");
}
finally{
// 用在异常捕获try...catch中
// 不管try块中的语句是否出现异常,finally一定会被执行
// 关闭文件,数据库连接。。。。
System.out.println("程序结束");
}
System.out.println("main方法结束运行");
}
}
案例2:throws关键字应用
定义一个方法的时候可以使用throws关键字声明。使用throws关键字声明的方法表示此方法不处理异常,而交给方法调用处进行处理。
public class Throws {
int a=1;
int b=0;
public void out() throws ArithmeticException{ //声明可能要抛出的异常,可以有多个异常,逗号隔开
try{ //监听代码块
int sum=a/b;
System.out.println(sum);
}
catch(ArithmeticException e){
System.out.println("分母不能为0");
}
finally{ //不管是否出现异常,finally一定会被执行
System.out.println("程序结束");
}
}
public static void main(String[] args){
Throws t=new Throws();
t.out(); //调用方法
throw new ArithmeticException("分母为0抛出异常"); //由调用的方法决定是否要抛出异常
/*
* 第二种抛出方式
*/
// ArithmeticException a=new ArithmeticException("分母为0抛出异常");
// throw a;
}
}
注意事项:
- 异常形参对象:
- 对象已经实例化成功,可以直接调用对象中的方法。
- 打印异常堆栈信息:e.printStackTrace();
- 打印异常信息: e.getMessage();
- 将异常抛出,让下一个对象去处理这个异常。
- throw:人为的抛出异常。
- throws:声明异常,声明这个主法会出现异常。必须对异常进行处理。
- 一个try可以跟多个catch();
- catch异常时,必须先捕获小的异常,再捕获大的异常。 throws也是一样。
- 捕获异常时,必须对异常进行处理。
- 不要把所有的代码放到try块试着执行。(try块要在内存中试着执行
总结:
- 错误不是异常,而是脱离程序员控制的问题。
- 所有的异常类是从 java.lang.Exception 类继承的子类。
- 异常类有两个主要的子类:IOException 类和 RuntimeException 类。
- Java有很多的内置异常类。
三、自定义异常
在 Java中你可以自定义异常。如果要自定义异常类,则扩展Exception类即可,因此这样的自定义异常都属于检查异常(checked exception)。如果要自定义非检查异常,则扩展自RuntimeException
自定义的异常应该包含如下的构造函数:
一个无参构造函数
一个带有String参数的构造函数,并传递给父类的构造函数。
一个带有String参数和Throwable参数,并都传递给父类构造函数
一个带有Throwable 参数的构造函数,并传递给父类的构造函数。
其中,必须有无参构造,至少一个带参构造。
public class TestSelfException05 extends Exception {
public TestSelfException05() {
}
public TestSelfException05(String msg) {
super(msg);
}
public static void main(String[] args) {
// 实现数组越界异常
int[] arr = new int[2];
System.out.println(test(arr, 1));
System.out.println(test2(2, 0));
}
private static int test2(int i, int j) {
if (j == 0) {
try {
throw new TestSelfException05("第16行代码第二个参数为0!!");
} catch (TestSelfException05 e) {
System.out.println(e.getMessage());
}
return 0;
}
return i/j;
}
private static int test(int[] arr, int i) {
int length = arr.length;
if (i < 0 || i >= length) {
try {
throw new TestSelfException05("第13行代码出错");
} catch (TestSelfException05 e) {
// e.prijavantStackTrace();
System.out.println(e.getMessage());
}
return 0;
}
return arr[i];
}
}
四、拓展
finally,final,finalize区别
- finally:异常处理里面最终要执行代码块
- final:表示最终的
- 类前面--类不能被继承
- 方法前面--方法不能被覆盖
- 变量前面--不能被重新赋值,表示常量
- 类前面--类不能被继承
- finalize():是Object的一个方法 垃圾回收的时候执行的方法
try、catch、finally的return问题
- finally的代码块会在try或者catch的return之前执行,假如finally中存在return,则整个方法的返回值就是finally中代码的return的值。
- 原因:try、catch中有return时,会将return的值先暂存起来,如果finally中有return,那就return finally中的值。如果finally中没有return,那就return try或catch中暂存的return的值。
- 首先一个不容易理解的事实:
- 在 try块中即便有return,break,continue等改变执行流的语句,finally也会执行。
- finally中的return 会覆盖 try 或者catch中的返回值。
- finally中的return或异常会抑制(消灭)前面try或者catch块中的异常
public static void main(String[] args) {
try {
int i = test2();
System.out.println("test2 返回值="+i); //3
} catch (Exception e) {
System.out.println("在main 获取方法传递上来的 异常对象信息:"+e.getMessage());
}
}
private static int test2() throws Exception {
try {
test1();
return 1;
} catch (Exception e) {
System.out.println("在try..catch中的 catch块中 异常处理");
return 2;
}finally {
System.out.println("test2的finally最后被执行。。");
return 3;
}
}
private static void test1() throws ArithmeticException{
Scanner sc = new Scanner(System.in);
System.out.println("输入两个整型数据:");
int a = sc.nextInt();
int b = sc.nextInt();
if (b == 0) {
//通过throw抛出异常对象,再由throws向上传递异常对象
throw new ArithmeticException("分母不能为0");
}else {
double value = a / b;
System.out.println("结果:"+value);
}
}
error和exception有什么区别
- Error:系统级的错误,程序无法处理,需要通过修改代码解决
- Exception:运行期间的例外对象,可以通过代码处理异常,避免中断程序执行
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 Eternal Night
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果