try-catch-finally异常处理的两种⽅式
异常处理
1. 明确什么是异常(重点)
2. 能辨识出常见的异常及其含义。(熟悉+)
3. 理解异常产⽣的原理(了解)
4. 能处理异常(重点)
5. 能够⾃定义异常类型(熟悉)
⽬的
我们发现异常,捕获异常的⽬的是要对异常进⾏补救,⽽不是打印⼀下。
什么是异常?
异常是在程序中导致程序中断运⾏的⼀种指令流。
例如,现在有如下的操作代码:
public class ExceptionDemo01{
public static void main(String argsp[]){
int i = 10 ;
int j = 0 ;
System.out.println("============= 计算开始 =============") ;
int temp = i / j ; // 进⾏除法运算
System.out.println("temp = " + temp) ;
System.out.println("============= 计算结束 =============") ;
}
};
运⾏结果:
============= 计算开始 =============
Exception in thread "main" java.lang.ArithmeticException: / by zero
at ExceptionDemo01.main(ExceptionDemo01.java:6)
以上的代码在“int temp = i / j ;”位置处产⽣了异常,⼀旦产⽣异常之后,异常之后的语句将不再执⾏了,所以现在的程序并没有正确的执⾏完毕之后就退出了。
那么,为了保证程序出现异常之后仍然可以正确的执⾏完毕,所以要采⽤异常的处理机制。
处理异常
异常处理⼀般有两种⽅式,1.使⽤catch捕获异常; 2.使⽤throws关键字在⽅法声明时抛出异常
1.catch捕获异常
如果要想对异常进⾏处理,则必须采⽤标准的处理格式,处理格式语法如下:
try{
// 有可能发⽣异常的代码段
}catch(异常类型1 对象名1){
// 异常的处理操作异常补救
}catch(异常类型2 对象名2){
// 异常的处理操作异常补救
} ...
finally{
// 异常的统⼀出⼝
System.out.println("这⾥的代码⽆论是否出现异常都会执⾏,⼀般⽤于资源回收");
}
在进⾏异常的处理之后,在异常的处理格式中还有⼀个finally语句,那么此语句将作为异常的统⼀出⼝,不管是否产⽣了异常,最终都要执⾏此段代码。
⽆论异常是否发⽣,finally必然执⾏。读取⽂件,占⽤⽂件,读取数据库等,都在finally中释放,因为finally必然执⾏。⼀般⽤于资源回收。
try+catch的处理流程
1、⼀旦产⽣异常,则系统会⾃动产⽣⼀个异常类的实例化对象。
2、那么,此时如果异常发⽣在try语句,则会⾃动到匹配的catch语句执⾏,如果没有在try语句中,则会将异常抛出.
3、所有的catch根据⽅法的参数匹配异常类的实例化对象,如果匹配成功,则表⽰由此catch进⾏处理。
2.throws throw 抛出异常
在程序中异常的基本处理已经掌握了,但是随异常⼀起的还有⼀个称为throws关键字,此关键字主要在⽅法的声明上使⽤,表⽰⽅法中不处理异常,⽽交给调⽤处处理。
1.throws是函数⽅法抛出异常,⼀般写在⽅法的头部,⽤来抛出⼀些异常,本⾝不进⾏解决,抛给⽅法的调⽤者进⾏解决(try catch)
格式:返回值⽅法名称()throws Exception{ }
Integer类: public static int parseInt(String text)throws NumberFormatException
2.throw是语句抛出异常,出现于函数内部,⽤来抛出⼀个具体异常实例,throw被执⾏后⾯的语句不起作⽤,直接转⼊异常处理阶段
⼀般是⽤户⾃定义的RuntimeException运⾏时异常,然后使⽤throw抛出。
1public class Demo9 {
2public static void main(String[] args) {
3 }
4
5/**
6 * 异常是否抛出去, 应该站在哪个⾓度思考?
7 *
8 * 如果是因为传参导致异常 , 应该通过throws将异常抛出去.
9 *
10 * @param text
11 * @throws IOException : 因为传递的指令不对, 会导致此问题发⽣(s2=0时)
12*/
13public static void shutdown(String text) throws IOException {
14 Runtime().exec(text);
15 }
16/**
17 * 此⽅法⽤于求两个参数的和
18 * 会将两个参数转换为数字求和
19 * @param s1 字符串参数1
20 * @param s2 字符串参数2
21*/
22public static void sum(String s1,String s2){
23int sum = Integer.parseInt(s1)+Integer.parseInt(s2);
24 System.out.println("和是:"+sum);
25 }
26 }
1public class Person {
2private String name;
3private int age;
4
5public String getName() {
6return name;
7 }
8
9public void setName(String name) {
10this.name = name;
11 }
12
13public int getAge() {
14return age;
try catch的使用方法15 }
16
17public void setAge(int age) {
18if(age<0 || age>180){
19 RuntimeException e = new RuntimeException("年龄不合理");
20throw e;
21 }else{
22this.age = age;
23 }
24
25 }
26 }
异常体系结构
异常指的是Exception , Exception类,在Java中存在⼀个⽗类Throwable(可能的抛出)
Throwable存在两个⼦类:
1.Error:表⽰的是错误,是JVM发出的错误操作,只能尽量避免,⽆法⽤代码处理。
2.Exception:⼀般表⽰所有程序中的错误,所以⼀般在程序中将进⾏try…catch的处理。
RuntimeExcepion与Exception的区别
RuntimeException是Exception的⼦类,
catch(Exception e) 就是范围最⼤的捕获异常。如果为了⽅便,则可以将所有的异常都使⽤Exception进⾏捕获。
所有RuntimeException的⼦类即为⾮检查型异常;Exception的其余⼦类都为检查型异常。所谓“检查型异常”是指在源代码例必须显式地进⾏捕获处理,eclipse和idea都是⾃动编译的,当我们把代码写完
的时候,如果有红线提⽰或者错误提⽰,那么就是检查异常。也就是说,当你看到某个⽅法声明中可能抛出某个检查型异常,那么作为调⽤⽅必须考虑如何处理这个异常,否则编译器就是给出错误提⽰。
所谓“⾮检查型异常”,也就是运⾏时异常,编译的时候不会给错误提⽰,运⾏的时候有可能出现异常。如:⽤户输⼊0作为除数,就会出现异常。通常是可以通过编码加以避免的逻辑错误,具体根据需要来判断是否需要捕获,并不会在编译期强制要求。例如NullPointerException、ArrayIndexOutOfBoundsException等。也就是说,程序员应该通过合理编码来努⼒避免程序出现这类异常,或者说程序出现这类异常就是程序员的责任。
异常处理常见⾯试题
1. try-catch-finally 中哪个部分可以省略?
答: catch和finally可以省略其中⼀个, catch和finally不能同时省略注意:格式上允许省略catch块, 但是发⽣异常时就不会捕获异常了,我们在开发中也不会这样去写代码.
2. try-catch-finally 中,如果 catch 中 return 了,finally 还会执⾏吗?
答:finally中的代码会执⾏详解:
执⾏流程:
1. 先计算返回值,并将返回值存储起来,等待返回
2. 执⾏finally代码块
3. 将之前存储的返回值,返回出去;
需注意:
1. 返回值是在finally运算之前就确定了,并且缓存了,不管finally对该值做任何的改变,返回的值都不会改变
2. finally代码中不建议包含return,因为程序会在上述的流程中提前退出,也就是说返回的值不是try或 catch中的值
3. 如果在try或catch中停⽌了JVM,则finally不会执⾏.例如停电- -, 或通过如下代码退出 it(0)。
try中有return时,finally也会执⾏,这个return值在finally执⾏之前的try中已经准备好了,复制备份放⼊
了缓存。如果return返回的是基本数据类型,如int,那么finally中再给int赋值也不会改变return返回的值。如果return返回的是⼀个对象,那么复制到缓存中的是这个对象的地址,这时在finally中改变这个对象的值时,返回的值就是改变以后的值。
1public class Demo7 {
2public static void main(String[] args) {
3int a = haha();
4 System.out.println(a);
5 }
6public static int haha(){
7int a = 10;
8try{
9return a;
10 }catch(Exception e){
11
12 }finally {
13 a = 20;
14 }
15return 0;
16 }
17static class Person{
18int age;
19 }
20 }
以上输出结果是:10
因为finally执⾏之前,retrun 的a是10,这个值已经复制到缓存中,输出时,就i时输出缓存中的值。finally再改变a的值也不会被输出。 1public class Demo6 {
2public static void main(String[] args) {
3 Person p = haha();
4 System.out.println(p.age);
5 }
6public static Person haha(){
7 Person p = new Person();
8try{
9 p.age = 18;
10return p;
11 }catch(Exception e){
12return null;
13 }finally {
14 p.age = 28;
15 }
16 }
17static class Person{
18int age;
19 }
20 }
以上输出结果是:28
try中return的p对象,放到输出缓存中是P对象的地址。finally中改变的是这个地址中的值,所以输出的值就是改变之后的值。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论