Java-异常

概述

  • 异常:运行时期发生的不正常情况
  • 在java中用类的形式对不正常情况进行了描述和封装对象
  • 描述不正常的情况的类,被称为异常类
  • 以前正常流程代码和问题处理代码相结合,现在将正常流程代码、问题处理代码分离,提高阅读性
  • 其实异常就是java通过面向对象的思想将问题封装为对象,用异常类对其描述
  • 不同类用问题用不同的类进行具体的描述,比如角标越界,空指针等等。

体系

  • 问题很多,意味着描述的类也很多,将其共性进行向上抽取,形成了异常体系
  • 最终问题就分成了两大类
    • Throwable:(直译:可抛的)问题发生应该就可以抛出,让调用者知道并处理
    • 1、一般不可处理的 Error
    • 2、可以处理的 Exception
  • 该体系的特点就在于 Throwable 及其所有的子类都具有可抛性
  • 可抛性是怎么体现的那?
    • 通过throws throw 这两个关键字所操作的类和对象都具备可抛性
  • 该体系特点:
    • 子类的后缀名都是用其父类名作为后缀,阅读性很强

Error

  • JVM抛出的严重性问题,这种问题发生一般不针对性处理,直接修改程序
1
2
3
4
5
6
public class ExceptionDemo {
public static void main(String[] args){
int[] arr = new int[1024*1024*800];
//java.lang.OutOfMemoryError: Java heap space
}
}

Exception

  • 分为两种:
  • 编译时受检测异常:Exception和其子类都是,除了特殊子类RuntimeExcetion
    • 这种问题一旦出现,希望在编译时就进行检测,让这种问题有对应的处理方式。
  • 编译不检测异常(运行时异常):RuntimeExcetion和其子类
    • 这种问题的发生,让功能无法继续,运算也无法进行,更多是因为调用的原因导致的,或者引发程序内部状态改变,导致的异常。这种问题一般不处理,直接编译通过,在运行时,调用者调用时引发异常从而程序强制停止,此时调用者即可对异常进行修正。

过程

  • 运到识别的问题,对象进行封装
  • 把问题抛给调用者
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Demo {
public int method(int[] arr,int index){
if(arr == null)
throw new NullPointerException("你咋空指针了");
if(index >= arr.length)
throw new ArrayIndexOutOfBoundsException("兄台,数组越界了,角标是:"+index);

return arr[index];
}
}
public class ExceptionDemo {
public static void main(String[] args){
int[] arr = new int[3];
Demo d = new Demo();
d.method(arr, 30);

}
}

自定义异常

  • 对于角标是整数不存在,可以用角标越界表示,对于负数角标的情况,准备用负数角标异常表示,但是这在Java中没有定义过,那就按照Java异常的创建思想,面向对象,将负数角标进行自定义描述,并封装成对象,这种自定义问题描述称为自定义异常。
  • 注意:如果让一个类称为异常类,必须要继承异常体系,因为只有称为异常体系的子类才有资格具备可抛性。才可以被两个关键字所操作 throws throw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    class FuShuIndexException extends Exception{
FuShuIndexException(){}
FuShuIndexException(String msg){
Super(msg);
}
}

class Demo{
public int method(int[] arr,int index) throws FuShuIndexException{
if(arr==null)
throw new NullPointerException("数组的引用不能为空");

if(index >= arr.length)
throw new ArrayIndexOutOfBoundsException("数组角标越界=" + index);

if(index < 0)
throw new FuShuIndexException();

return arr[index];
}
}
public class ExceptionDemo {
public static void main(String[] args) throws FuShuIndexException {
int[] arr = new int[3];
Demo d = new Demo();
d.method(arr, -1);
}
}
  • 自定义的异常,要么继承Exception,要么继承RuntimeException

抛出 throw

  • throw和throws区别:
    • throws使用在函数上,抛出的是异常类,可以跑出多个,用逗号隔开
    • throw使用在函数内,抛出的是异常对象

捕捉 catch

  • 可以对异常进行针对性处理的方式
1
2
3
4
5
6
7
8
具体格式:
try{
//需要被检测异常的代码
}catch(异常类 变量){ //该变量用于接收发生的异常对象
//真正处理该异常的代码
}finally{
//一定会被执行的代码
}
  • 下面是演示代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Demo {
public int method(int[] arr,int index){
if(arr == null)
throw new NullPointerException("你咋空指针了");
if(index >= arr.length)
throw new ArrayIndexOutOfBoundsException("兄台,数组越界了,角标是:"+index);
return arr[index];
}
}
public class ExceptionDemo {
public static void main(String[] args){
int[] arr = new int[3];
Demo d = new Demo();
try {
int num = d.method(null, 30);
System.out.println(num);
}catch (NullPointerException e){
System.out.println(e.toString());
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("message:"+e.getMessage());
System.out.println("String:"+e.toString());
//e.printStackTrace();//Jvm默认处理机制就是调用异常这个方法
System.out.println("越界");
}/*catch (Exception e){
//多catch,父类的catch放在最下面
}*/
}
}

finally代码块

  • 除了在catch中强制关闭JVM的情况下,finally中的语句都会被执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
情况1:
运行结果:finally
*/
try {
//需要被检测异常的代码
}catch (NullPointerException e){
//处理异常的代码
return;
}finally{ //通常用于关闭(释放)资源
System.out.println("finally");
}
System.out.println("Over");

/*
情况2:去掉第9行的return后,运行
结果:finally Over
*/

try catch finally 代码组合特点

  • 1、try catch finally
  • 2、try catch(多个)
    • 没有必要资源需要释放时,可以不用定义finally
  • 3、try finally
    • 异常无法直接处理,但是资源需要关闭
1
2
3
4
5
6
try{
//开启资源
throw new Exception;
}finally{
//关闭资源
}

异常处理原则

  • 1、函数内部如果抛出需要检测的异常,函数上必须要声明,否则必须在函数内用trycatch捕捉,否则编译失败
  • 2、如果调用到了声明异常的函数,要么trycatch,要么throws,否则编译失败
  • 3、什么时候catch,什么时候throws那?
    • 功能内容可以解决,用catch
    • 解决不了,用throws告诉调用者,由调用者解决
  • 4、一个功能如果抛出了多个异常,那么调用时,必须有对应多个catch进行针对性的处理,内部有几个需要检测的异常,就抛几个异常,抛出几个,就catch几个

异常应用

  • 用Java描述老师上课,需要电脑,电脑会出现蓝屏冒烟两种故障
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class LanPingException extends Exception {
LanPingException(String msg){
super(msg);
}
}
public class MaoYanException extends Exception {
MaoYanException(String msg){
super(msg);
}
}
public class Computer {
private int state = 0;
public void run() throws LanPingException, MaoYanException {
if (state == 1)
throw new LanPingException("蓝屏");
if (state == 2)
throw new MaoYanException("冒烟");
System.out.println("computer run");
}
public void reset(){
state = 0;
System.out.println("电脑重启");
}
}
public class Teacher {
private String name;
private Computer comp;
public Teacher(String name){
this.name = name;
comp = new Computer();
}
public void prolect() throws MaoYanException{
try {
comp.run();
System.out.println(name+"讲课");
}catch (LanPingException e){
e.getMessage();
comp.reset();
prolect();
}catch (MaoYanException e){
System.out.println(e.toString());
practice();
throw e;
}
}
public void practice(){
System.out.println("电脑坏了,大家练习");
}
}
public class Demo {
public static void main(String[] args){
Teacher t = new Teacher("cheng");
try {
t.prolect();
} catch (MaoYanException e) {
System.out.println("......");
}
}
}
  • 数据库连接出现异常怎么解决那
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class NoAddException extends Exception{

}

void addData(Data d) throws NoAddException{
连接数据库
try{
添加数据,出现异常
}catch(NoAddException e){
//处理代码
throw new NoAddException();
}finally{
关闭数据库
}
}

注意事项

  • 1、子类在覆盖父类方法的时候,父类的方法如果抛出了异常,那么子类的方法只能抛出父类的异常,或者该异常的子类
  • 2、如果父类抛出多个异常,子类只能抛出父类异常的子集

  • 简而言之:子类覆盖父类方法时,只能抛出父类异常或异常子类或子集

  • 注意:若父类方法没抛出异常,子类覆盖时绝对不能抛出异常,只能try