异常:针对代码中的非正常情况进处理的
目录
1.无参构造方法 new RuntimeException();
九、当以异常的方式体现时:错误 vs 受查异常(检查异常) vs 非受查异常
一、处理异常的方法
理论上的方法:
1.继续运行
继续运行,没有任何形式,但程序从此进行 行为未定义 状态,出现啥情况都是合理的。 int a[10] = { ... } a[19]这个用法错误。(这并不是一个好的处理办法,因为造成的问题就是:案发现场往往不是第一作案现场。)
2.想办法告诉调用者出错
①通过返回值告诉对方:结果的值如果是xx,做说明计算错误了,如果是xx,说明计算正确了。
②异常的方式,可以很好的避免上述的两种缺点。采用异常机制(性能方面往往有重大损失)
3.使用try-catch
异常情况和正常情况完全分离:异常走 throw 异常对象;正常走 return 形式
二、异常中的关键字
try、catch、finally、throw、throws
try + catch、try + finally、try + catch + finally
try{
//没发生错误时,正常的语句
} catch(异常的类型 变量名){
}catch(RuntimeException exc){
//在遇到RuntimeException,我需要怎么办
}finally{
//最终
//无论是正常执行完、还是异常执行完,都需要执行这里的语句
}
谁对异常负责,谁写try-catch
三、throw 抛出异常
案发现场(异常现场)负责 抛出(throw)一个异常对象
//写法1
throw new RuntimeException(...);
//写法2
RuntimeException e = new RuntimeException();
throw e;
一个异常对象,异常情况的抽象,Java中规定了可以被抛出的继承体系。
记录:发生了什么问题:异常的类型;具体描述:属性Massage ;在什么情况下发生的问题,异常发生时的调用栈来体现。
实际上,还有很多没有列出来,我们也可以实现自己的异常,通过继承Exception、RuntimeException
public class RuntimeException extends Exception{ }
四、异常对象的构造方法和常见方法
1.无参构造方法 new RuntimeException();
2.允许传入String Message
new ArrayIndexOutOfBoundsException("1超过了下标范围");
3.通过一个异常,构造另一个异常
例如:饭不够吃Exception e = ...; 物资不够Exception exc = new 物资不够Exception(e); 现在的问题是物资不够,但底层的现象是饭不够吃。这就是由于 e 的异常,导致的 exc 的异常。
另外:当一个异常被main 抛出时,说明应用代码中谁都不会对此事负责,则程序终止运行。
五、标准输出和标准错误
标准输出(一般用来输出非错误信息) =》 目的地默认的情况下都是 控制台(屏幕) Java程序中输出内容的通道
标准错误(一般用来输出错误信息) =》 目的地默认的情况下都是 控制台(屏幕)
六、catch 的逻辑:
假设调用链条如下:main(); -> aa(); catch(AException、BException)
-> bb(); -> cc(); catch(CException、DException)
-> dd(); catch(AException、DException、EException)
-> ee(); catch(FException) -> ff();
A-F Exception 之间不存在任何继承关系,本例子 异常上报方向,从 ff() 到 main()
抛出了FException ,ee(); 负责处理; 抛出了BException ,aa(); 负责处理
抛出了AException ,dd(); 负责处理; cc 中抛出了AException,aa();负责处理
ff 中抛出了 HException,无人负责,最终 JVM 负责(解决办法,中止程序)
例:AException——BException CException ; B继承自A
try{
ff();
}catch(AException exc){
//执行 a 逻辑
}catch(BException exc){
//指行 b 逻辑
}catch(CException exc){
//指行 c 逻辑
}
问:ff() 抛出了 AException,执行什么逻辑?——a逻辑
ff() 抛出了 CException,执行什么逻辑?——c逻辑
ff() 抛出了 BException,执行什么逻辑?——a逻辑,不会执行b 逻辑,因为 b 继承 a ,BException 对象其实也是AException
七、throw vs throws
throw:用来抛异常 throws:声明风险
public void 防控疫情(...) throws 物资短缺,经济下滑{ ... }
八、写代码的时候可能有两大类代码错误
1.语法错误 -> 编译错误(编译就失败了)
2.运行时错误 -> 语法没问题,执行处出问题;①以异常方式体现②没有异常,只是运行结果不符合预期
九、当以异常的方式体现时:错误 vs 受查异常(检查异常) vs 非受查异常
错误:因为设备(或者其他硬性环境导致的,程序根本无法修复的问题,比如:CPU烧了、硬盘烧了)
受查异常:一些可以通过重试、或者程序自动修复可以解决的问题(暂时上不了网,内存暂时不够用)
非受查异常:因为程序的代码 BUG 导致的问题(空指针异常、数组下标越界异常、除 0 异常)
设计的理念中:我们应该catch 受查异常。错误,我们catch 也解决不了。非受查异常,就不应该 catch
继承自 Error 的,就是错误(也可以算一种非受查异常);继承自 RuntimeException ,就是非受查异常;继承自 Exception ,但不是 RuntimeException 子类的,是受查异常
java针对受查异常,强制要求:1.一个方法如果抛出了受查异常,则必须通过 throws 声明异常
2.方法如果抛出的是非受查异常,则可以声明,也可以不声明异常
受查异常使得代码具备了传染性:实践中的常见做法,用一个非受查异常把受查异常包起来。
private static void method() throws IOException{
//受查异常
throw new IOException();
}
public static void method1() {
try{
method();
}catch(IOException exc){
throw new RuntimeException(exc);
}
}
public static void main(String[] args) {
method1();
}