java进阶-第七讲 异常

第七讲 异常

1 什么是异常?

异常就是不正常。
比如:一个正常人,感冒发烧生病,就是这个人异常了。
当一个人感冒了,没有吃药,表面上没有处理,但是不影响他正常生活,是不是身体内部
的免疫系统帮他处理了这个感冒!
比如一个人得了新冠肺炎,不处理行吗?不处理这个人可能面临生命危险。
这种病毒,人的身体内的免疫系统处理不了,如果不主动处理,就会出事。

比如:在java中,我们进行类型转换的时候,有可能出现类型不匹配,无法转换,强制转的就会发生异常。
举例:
public class ExceptionTest01 {

    public static void main(String[] args) {
        int res = 100 / 0;// ArithmeticException: / by zero
        System.out.println(res);
        System.out.println("hello");
    }
}
//Exception in thread "main" java.lang.ArithmeticException: / by zero
// 程序一旦发生异常,如果没有处理机制,一旦发生,程序就会终止运行。
// 这样好不好?不好
// 这说明程序的健壮性不好。
// java给我们提供了异常的处理机制。对于一些可以预见到的异常,我们可以事先处理
// 比如:在写代码的时候,我们可以将这些异常处理了
// 避免在运行时出现问题。

// lr是生活委员,管着班级的钱,100万在黎睿手上,这时候lr弄丢了10万块。
// 这时候是不是就发生异常了。
// 怎么办呢?这笔钱是一笔大数目,两种方式,一种就是上报给xjf,xjf报给我,
// 我报给yz,yz报给xz....一直得不到处理,最后JVM终止运行。


// 一个司机开车撞人了,解决方法:报警
// 解决方案2:私了

2 java中的异常是什么?

java中定义了很多异常类,他就是一个普通的类。产生一些普通的对象。
只不过这些类与程序中出现的异常相关。是为了处理异常而开发出来的。
首先,我们来看看异常的继承关系:

注意两个概念:
	写代码的时候,编译时报错的异常,就是编译时异常
	写代码的时候,编译时没有报错的异常,就是运行是异常(RuntimeException)

在这里插入图片描述

3 编译时异常怎么处理?

两种处理方式:
1. 上抛,throws 也就是说,我没能力处理,报给上一个调用我的方法
	上一个也可以继续上抛,一直抛到main方法上。main方法再上抛就会抛给JVM
	JVM就会中断运行。
	对于编译时异常,一直上抛,说明只是把问题抛给了更高一级,并没有实实在在的处理它
2. 捕获异常
	try{}catch(){}
	也就是说,一旦异常发生,可以上抛,但是在没有到达main方法之前,最好捕捉并处理。
	不要将这些异常交给JVM自动处理。

4 处理异常的方式

方式1:上抛 语法格式:throws 异常类的类名
throws关键字出现在方法声明的()后 {之前。
private static void m4() throws FileNotFoundException { 方法体}

编译时异常一定要捕获,一定要处理,如果不做任何处理,编译过不了。
如果一味上抛,一旦出现问题,jvm会终止运行。
异常一旦发生且被捕获之后,程序是不会终止运行的。
打印出来的信息叫做堆栈追踪信息
它是告诉开发人员,问题出在哪里。
e.printStackTrace()这个方法是异常中最重要的一个方法。
一般都使用这个方法,这个方法出现在cath语句块中。

详细介绍try...catch
try: 尝试
catch:捕捉,捕获,抓住
try {
	java语句;
}
大括号是一个作用域,在这里面定义的变量,出了这个作用域就失效了。
如果try语句块中没有要处理的异常信息,
catch是一个可以省略的,但是不建议省略。
try只会在有异常发生的情况下才会出现。
如果只有try是不行的。
catch() {}
catch(异常类的变量)

try {
    m1();
} catch (FileNotFoundException e) {
     e.printStackTrace();
}
m1()方法抛出的异常类型是什么,catch()的参数一定要是这个类型,或者是其父类型。
try...catch的执行过程:
try 语句块中的m1()方法执行,这时候异常发生,那么如果m1()方法后面还有其他的语句,将不会执行。
这时候程序进入到catch语句块中执行,这时候先检查catch()中的参数类型,是否是m1()抛出的异常类型,或者是其父类型(如果是父类型,就是多态的机制),然后打印具体的堆栈追踪信息。
执行完毕后,程序依然向下顺序执行。
如果try语句块中的m1()方法没有发生异常,catch语句快不会被执行。

5 (最重要的部分)手动抛异常:自定义异常

public class NumException extends Exception {
    private String message;

    public NumException() {
    }

    public NumException(String message) {
        this.message = message;
    }
}

自定义异常类如上:就是固定写法。
    成员属性String类型
    两个构造,一个无参一个有参
    最最重要的:extends Exception
    不能继承RuntimeException
    
手动抛异常:
public class Num {
    public void check(Object object) throws NumException {
        if (object instanceof Integer) {
            System.out.println("合法的整数");
        } else {
            NumException ex = new NumException();
            throw new NumException("不是合法的整数!");
        }
    }
}
注意:一定要有关键字throw 不是throwsthrows的放在方法()后面
    throw用在方法体内
    throw new 要抛的异常类();
	throw new :配合使用。
        
测试类:
public class Test {

    public static void main(String[] args) {

        Num num = new Num();
      
        try {
            num.check("123123123");// 继承RuntimeException编译时是能通过的
        } catch (NumException e) {
            e.printStackTrace();
        }
        // 继承RuntimeException是没有意义的
        // 运行时异常,你即便是在方法上抛了异常,编译器也不会理
        // 它就认定这就是运行时异常,不归编译器管。
        // 说白了,如果是个异常都要处理,人要崩溃。
        // 并不是所有的异常都要捕获,如果都要捕获,是做不到的。
    }
}

6 如何阅读控制台输出的异常信息

java.io.FileNotFoundException: F:\Is\Study\src\com\tj\exceptionTest\ExceptionTest01.java (系统找不到指定的路径。)
	at java.io.FileInputStream.open0(Native Method)
	at java.io.FileInputStream.open(FileInputStream.java:195)
	at java.io.FileInputStream.<init>(FileInputStream.java:138)
	at java.io.FileInputStream.<init>(FileInputStream.java:93)
	at com.tj.exceptionTest.ExceptionTest02.m4(ExceptionTest02.java:45)
	at com.tj.exceptionTest.ExceptionTest02.m3(ExceptionTest02.java:40)
	at com.tj.exceptionTest.ExceptionTest02.m2(ExceptionTest02.java:34)
	at com.tj.exceptionTest.ExceptionTest02.m1(ExceptionTest02.java:28)
	at com.tj.exceptionTest.ExceptionTest02.main(ExceptionTest02.java:17)
    
    
一旦发生异常:就是自己的代码写错了。
    错就错在自己的代码错了,SUN写的代码不会错。因为他们只定义了异常
    抛出了异常,要求我们自己处理。
    我们处理异常,但是异常还是发生了,而且报告了位置,那么要找就要找我们自己
    写的代码中哪个位置出错了。
    但是我们处理了异常,说明程序能够正常往下执行。不会中断。JVM不会终止。
    假如我们写的是服务器,服务器就不会down机。
    
怎么看异常出现在哪里?
    1. 看自己写的代码,在打印的堆栈追踪信息中去找
    2. 找自己代码部分最上面的一条堆栈追踪信息。

7 总结try–catch

try..catch不能避免异常,只能确保异常发生以后,程序还能正常运行
但是在try代码块中,异常发生之后,这个异常所在位置之后的代码都将不会执行。
这是在try语句块中。
异常发生后,执行catch语句块中的内容,主要是打印堆栈追踪信息,还有一些日志信息
在idea中,遇到编译时异常,直接alt + enter键,使用try..catch..

自定义异常,一定不能继承RuntimeException。一般都是继承Exception
如果知道具体的异常子类,可以直接继承具体的子类。

catch代码块可以有多个,但是其中的参数一定要从小到大,不能前面是父类,后面是子类
父类会覆盖子类。编译器报错。

jdk1.8以后的新特性:简化多个catch代码块带来的代码臃肿
catch (NumException | FileNotFoundException e)
我们建议能精确就精确,有利于代码的可阅读性

异常的主要作用是提高代码的健壮性。

8 finally子句

finally语句块,一定要联合try使用,没有try这个关键字不起作用
不论try中发生了什么事情,finally子句都会执行。没有异常也会执行。
private static int m() {
        int i = 100;
        try {
            return i;
        } finally { 
//一定要在方法结束之前执行。
// finally一定要和try连用。finally只有在try语句块中有最终执行权
            i++;
        }
    }

返回的i值为100.
    具体的做法如下:
private static int m() {
    byte i = 100;
    byte var1;
    try {
         var1 = i;
    } finally {
         int var5 = i + 1;
    }
   return var1;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值