Loading

Java异常相关知识总结

 

 

异常:

概述:java程序运行过程中出现的错误

常见的异常:
StackOverflowError
ArrayIndexOutOfBoundsException
NullPointerException
ClassCastException
ParseException

异常的分类:
Trowable:
  1.--Error: a.相当于天灾人祸,虚拟机出现了问题
  2.--Exception:
    1).RuntimeException:运行过程中出现的异常 可以处理可以不处理,一般出现这种问题都是代码逻辑有问题,推荐修改代码
    2).编译期异常:出发之前因该检查的异常,必须处理,负责编译不通过

 

1,编译时异常: 除了RuntimeException及其子类,Exception中所有的子类都是,这种异常必须要处理,要不编译通不过。

2,运行时异常 :RuntimeException及其子类都是,这种异常不用处理,编译会通过,不过这样的程序会有安全隐患,遇到这种异常是需要改代码的。

3,严重错误问题 :用Error进行描述,这个问题发生后,一般不编写针对代码进行处理,而是要对程序进行修正.通常都是由虚拟机抛出的问题。

举例说明:

异常分三类: 骑车去旅行:
  Error:走到半路上,发生山路塌陷,或者出现了泥石流,这个问题很严重,不是班长能够立马解决的。
  Exception:出门前,班长要看看车轮子以及车链子等是否还在
  RuntimeException:在骑车的过程中,有好路不走,偏偏要走石子路

异常举例:

 1 //异常测试:
 2 //  a.除数为0
 3 //  b.数组越界
 4 public class HomeWork_02 {
 5     public static void main(String[] args) {
 6         System.out.println("start");
 7         f1();
 8         //f2();
 9         System.out.println("end");
10     }
11     //数组越界异常
12     public static void f2(){
13         int[]arr={1,2,3};
14         System.out.println(arr[0]);
15         System.out.println(arr[1]);
16         System.out.println(arr[2]);
17         //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3
18     }
19     //除数为0异常
20     public static void f1(){
21         int a=23;
22         int b=0;
23         System.out.println(a/b);//ArithmeticException: / by zero
24     }
25 }

jvm对异常的默认处理:
a. 哪个线程出现的问题
b. 异常的类型以及详细信息
c. 调用栈信息
d. 终止程序

如下图为异常举例代码中数组溢出是jvm所报的错误:

 

 



 因为jvm处理异常的时候直接停止了程序,所以我们要学会自己处理异常:

如何自己处理异常:
  a. try...catch...finally  
  b. throws


 


 

1. try...catch...finally语句
  try {
  要检查的代码
    } catch (异常类型 对象名) {
      对异常的处理
   } finally {
    释放资源
  }
a. 一种异常的情况

 1 public class ExceptionDemo_03 {
 2     public static void main(String[] args) {
 3         System.out.println("Start");
 4         int a =10;
 5         int b=0;
 6         try{
 7             System.out.println(a/b);
 8             System.out.println("one");
 9             System.out.println("two");
10             System.out.println("three");
11         }catch(ArithmeticException e){
12             System.out.println("除数为0");
13             System.out.println(e);
14         }
15         System.out.println("end");
16     }
17 }
//问题:为什么e局部变量会有值?

//如果try里面出现了异常, JVM会把异常信息封装成对应类型的异常对象。

 //然后和catch语句依次匹配,找到对应的异常类型,然后把它赋值给引用变量e

输出结果:

注意事项:
a. try里面的代码越少越好,最好只放可能出现异常的代码
b. try里面出现了异常,就不会执行try里面里面后序的代码
c. ArithmeticException e 是局部变量, 作用范围是对应的catch语句。
d. catch 捕获了异常,执行对应的处理,异常就不再存在了。

 

b.多种异常的情况:
    a. 一个一个处理
    b. 一次性处理
    c. JDK7 新特性
      把多个处理方式相同的catch语句,合成一个catch语句。
        catch(类型1 | 类型2 | 类型3... e)
注意事项:
一个try语句中, 最多只会抛出一个异常,最多也只会执行一个catch语句
如果异常没有兼容惯性,谁先谁后没关系,如果有兼容关系,那么父类应该方法在子类之后。
JDK7新特性, 一个catch 语句不能出现子父类关系

测试代码:

 1 /*多种异常的情况:
 2         a. 一个一个处理
 3         b. 一次性处理
 4        处理方式相同的catch语句,合成一个catch语句。
 5         catch(类型1 | 类型2 | 类型3... e)*/
 6 public class ExceptiomDemo_04 {
 7     public static void main(String[] args) {
 8         System.out.println("start");
 9         /*try {
10             f1();
11             f2();
12             // f2()在后面的时候,执行到f1()的时候就不再往下执行了,没有输出arr[0],arr[1],arr[2]
13         } catch (ArithmeticException e) {
14             // System.out.println("除数为0");
15             System.out.println("发生了异常");
16         } catch (ArrayIndexOutOfBoundsException e) {
17             // System.out.println("数组索引越界");
18             System.out.println("发生了异常");
19         } catch (Exception e) {
20             System.out.println("其他异常");
21         }*/
22         try {
23             f2();
24             f1();
25         } catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
26             System.out.println("除数为0或者数组索引越界");
27         }
28 
29 
30     }
31     public static void f2(){
32         int []arr={1,2,3};
33         System.out.println(arr[0]);
34         System.out.println(arr[1]);
35         System.out.println(arr[2]);
36         System.out.println(arr[3]); // ArrayIndexOutOfBoundsException: 3
37     }
38     public static void f1(){
39         int a =10;
40         int  b=0;
41         System.out.println(a/b);// ArithmeticException: / by zero
42 
43     }
44 }
45   

 

 



 


编译期异常和运行时异常:
Exception:
  |-- 运行时异常: RuntimeException和其子类。
可以显示处理,也可以不处理,一般出现运行时异常,都是代码逻辑有问题,推荐修改代码逻辑。
  |-- 编译期异常:其他类。无论运行时是否发生异常,都必须显示处理,否则无法通过编译。
测试代码:

 1 import java.text.ParseException;
 2 import java.text.SimpleDateFormat;
 3 import java.util.Date;
 4 import java.util.SimpleTimeZone;
 5 
 6 //编译期异常和运行时异常:
 7 public class ExecptionDemo_05 {
 8     //一般不要在主方法中抛出异常,这里为方便在主方法中抛出异常
 9     public static void main(String[] args) throws ParseException {
10         //运行时异常:
11         int a=10;
12         int b=0;
13         try{
14             System.out.println(a/b);
15         }catch(ArithmeticException e){
16             System.out.println("除0异常");
17         }
18         //编译期异常,不解决不能通过编译
19         Date time=new Date();
20         SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
21         String date=sf.format(time);
22         System.out.println(date);
23         Date date1=sf.parse(date);//ParseException 
24     }
25 }

 



 

Throwable

Throwable 类是 Java 语言中所有错误或异常的超类。只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。

类似地,只有此类或其子类之一才可以是 catch 子句中的参数类型。

  构造方法摘要: 
    Throwable()
      构造一个将 null 作为其详细消息的新 throwable。
    
Throwable(String message)
      构造带指定详细消息的新 throwable。
  成员方法:
   

      返回此 throwable 的详细消息字符串。

      默认实现:getClass().getName()+“:”+getMessage();
      返回此 throwable 的简短描述。
    void printStackTrace() //推荐使用它,而且输出内容会用红色标识
        将此 throwable 及其追踪输出至标准错误流。

注意:通常e.getMessage()并不能获取全部的错误信息,需要用到e.printStackTrace()查看完整错误信息,但是这个方法是void 只能在控制台输出

测试代码:

 1 import java.text.ParseException;
 2 import java.text.SimpleDateFormat;
 3 import java.util.Date;
 4 
 5 //Throwable():、
 6 public class ExceptionDemo_06 {
 7     public static void main(String[] args) {
 8         String s = "2001/01/01 00:00:00";
 9         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
10         Date date = null;
11         try{
12             date=sdf.parse(s);
13         }catch(ParseException e){
14             System.out.println("解析异常");
15             System.out.println(e.getMessage());
16             System.out.println(e.toString());
17             e.printStackTrace();
18         }
19     }
20 }

 

 



 

thorws

定义功能方法时,需要把出现的问题暴露出来让调用者去处理。那么就通过throws在方法上标识。
举例:
村里出现了问题,如果能自己解决就自己解决,解决不掉就交给乡里,乡里解决不掉就抛给县里解决, 县里解决不掉,抛给市里,如果市里解决不掉,抛给省里,如果省里解决不掉,抛给中央。中央就直接干掉。

throws: 把问题抛给调用者
a.编译期异常
b.运行期异常

注意事项:
不要在main()方法抛出异常,如果抛出异常就会执行JVM的默认处理。

测试代码:

 1 import java.text.ParseException;
 2 import java.text.SimpleDateFormat;
 3 import java.util.Date;
 4 
 5 public class ExceptionDemo_07 {
 6     public static void main(String[] args) {
 7         String s = "2019/7-9 11:31:00";
 8         String pattern = "yyyy-MM-dd HH:mm:ss";
 9         Date date = null;
10         try {
11             date = string2Date(s, pattern);
12         } catch (ParseException e) {
13             e.printStackTrace();
14         }
15         System.out.println(date);
16         int a = 10;
17         int b = 0;
18         int c = 0;
19         try {
20             c = f1(a, b);
21         } catch (Exception e) {
22             e.printStackTrace();
23         }
24         System.out.println("c = " + c);
25         System.out.println("end");
26     }
27     //throw:告诉调用者,注意:调用这个方法可能会有某某异常
28     public static Date string2Date(String s, String pattern) throws ParseException {
29         SimpleDateFormat sdf = new SimpleDateFormat(pattern);
30         return sdf.parse(s);
31     }
32     public static int f1(int a, int b) throws Exception{
33         // return a / b;
34         if (b != 0) {
35             return a / b;
36         }
37         throw new Exception("除0异常");
38     }
39 }

 

throw

在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。

 

测试代码:

 

throws和throw的区别
throws
用在方法声明后面,跟的是异常类名
可以跟多个异常类名,用逗号隔开 表示抛出异常,由该方法的调用者来处理
throws表示出现异常的一种可能性,并不一定会发生这些异常

throw
用在方法体内,跟的是异常对象名
只能抛出一个异常对象名
表示抛出异常,由方法体内的语句处理
throw则是抛出了异常,执行throw则一定会出现异常, throw抛出了一个实实在在的异常

 1 import java.util.Scanner;
 2 
 3 //举例:
 4        // 录入学生成绩 [0~100]
 5 public class ExecptionDemo_08 {
 6     public static void main(String[] args) {
 7         System.out.println("请输入学生成绩");
 8         Scanner sr =new Scanner(System.in);
 9         int score=sr.nextInt();
10         //数据验证
11         try{
12             checkScore(score);
13         }catch(Exception e){
14             e.printStackTrace();
15             
16         }
17     }
18     public static void checkScore(int score) throws Exception {
19         if(score<0||score>100){
20             throw new Exception("score="+score);
21         }
22         //throw抛出了异常后,后面的语句就不再执行
23         System.out.println("one");
24         System.out.println("two");
25         System.out.println("three");
26     }
27 }

 

 



 

我们到底该怎么处理异常:
原则:如果该方法知道如何处理,那用try...catch, 如果不知道怎么处理,就抛给它的调用者去处理。
区别:
  如果try...catch,后续代码会执行。
  如果throws,后续代码不会被执行。


try语句的变形
try...catch
try...finally
try...catch...finally
try...catch...catch...
try...catch...catch...finally

 



 


finally语句:
特点:
  被finally控制的语句体无论出现异常还是没有出现异常,都会执行。
  特殊情况:在执行到finally之前jvm退出了. System.exit();
作用:
  释放系统资源

final和finally和finalize区别:

final: 最终的
  类:不能被继承
  方法:不能被重写
  变量:常量
finally:
  try语句的子句。
  finally里面的语句, 无论出现异常还是不出现异常,都会被执行。  
  用来释放资源。
finalize:
  Object中的方法。
  对象被回收前,该方法会被自动执行。用来释放资源。
  手动调用该方法,对象不会被回收。

 1 import java.text.ParseException;
 2 import java.text.SimpleDateFormat;
 3 import java.util.Date;
 4 
 5 public class ExceptionDemo_09 {
 6     public static void main(String[] args) {
 7         String s = "2019/7/9 14:40:00";
 8         String pattern = "yyyy-MM-dd HH:mm:ss";
 9         SimpleDateFormat sdf = new SimpleDateFormat(pattern);
10         try {
11             Date date = sdf.parse(s);
12         } catch (ParseException e) {
13             e.printStackTrace();
14         //finally只有在执行到finally之前虚拟机就退出的时候才会不执行
15             //System.exit(0);
16         } finally {
17             System.out.println("finally子句");
18         }
19         System.out.println("end");
20     }
21 }            

 



 

 

如果catch里面有return语句,请问finally的代码还会执行吗?如果会,请问结果是怎样的?
finally语句会被执行
第一次执行return语句,就已经生成了返回路径, 并把返回值保存起来了。
后面在finally语句中修改变量,不会影响返回值。

如果finally中也有return语句。
最终执行的是finally中语句。

 1 public class ExceptionDemo10 {
 2     public static void main(String[] args) {
 3         System.out.println(method()); //40
 4     }
 5 
 6     public static int method() {
 7         String s = "2019/7/9 14:40:00";
 8         String pattern = "yyyy-MM-dd HH:mm:ss";
 9         SimpleDateFormat sdf = new SimpleDateFormat(pattern);
10         int a = 10;
11         try {
12             a = 20;
13             Date date = sdf.parse(s);
14         } catch (ParseException e) {
15             a = 30;
16             return a;
17         } finally {
18             System.out.println("finally");
19             a = 40;
20             return a; //生成了另外一条返回路径
21         }
22     
23     }
24 }    

 



 

 

自定义异常:
类名就代表异常的种类(信息)
编译期异常:继承Exception
运行时异常:继承RuntimeException

异常类:

1 public class ScoreException extends RuntimeException {
2     public ScoreException(){
3         super();
4     }
5     public ScoreException(String message){
6         super(message);
7     }
8 }

 

测试类:

 1 public class EceptionDemo_11 {
 2     public static void main(String[] args) {
 3         System.out.println("请录入学生成绩;");
 4         Scanner scanner = new Scanner(System.in);
 5         int score = scanner.nextInt();
 6         // 数据验证
 7         /*try {
 8             checkScore(score);
 9             // 存入数据库
10         } catch (ScoreException e) {
11             e.printStackTrace();
12         }*/
13         checkScore(score);
14     }
15     private static void checkScore(int score) throws ScoreException{
16         if (score < 0 || score > 100) {
17             // throw new RuntimeException("score=" + score);
18             throw new ScoreException("score=" + score);
19         }
20     }
21 }

 

异常注意的事项:(编译期异常)
子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。
如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常
如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws

儿子不能比父亲更坏。一代只能比一代强。
编译的时候,不检查运行时异常

posted @ 2019-07-10 20:03  半瓶牛奶🥛  阅读(303)  评论(0编辑  收藏  举报