异常

 

概念

  异常:程序在运行时出现不正常的情况

由来

  问题也就是现实生活中的一个具体事物,也可以通过JAV类的形式进行描述,并封装成对象,其实就是JAVA对不正常情况描述后的对象体现

分类

  可处理:Exception 

      运行时异常(unchecked exception):一般可以通过针对的处理方式进行处理,程序员完全可以根据自己的经验,提前预判会不会出问题

      非运行时异常【检查异常】(checked exception):程序员能够对其作出处理

  不可处理:Error

      一般不编写针对性的代码进行处理

Throwable
  Throwable 类是 Java 语言中所有错误或异常的超类[父类]

异常的处理

  异常分为2种

    1.编译时被检测的异常

    2.编译时不被检测的异常(运行时异常RuntimeException以及其子类)  

<---检查异常[checked]:需要我们人为的去处理--->

技巧:如果程序出现异常,我们应该怎么去观察

     错误的堆栈信息(先进后出),一般我们调用类的信息都在下面,就找认识的

示例

处理方法

  <-------捕获异常------->
            我有一辆车,车的杀出有点不好使,假如别人来借我的车,我需要把这个消息告诉他,他发现问题有点麻烦,直接自己就处理了
            别人在使用这个车的时候就没有刹车的问题

代码格式一

1 try【进行捕获】
2   {
3         可能出现异常的代码
4   }catch(异常类  变量){
5         具体处理方法
6   }catch(异常类  变量){
7         具体处理方法
8   }

示例代码

 1 public class Exam {
 2     public static void main(String[] args) {
 3         test();
 4     }
 5 
 6     public static void test() {
 7         try {
 8             InputStream inputStream = new FileInputStream("");
 9         } catch (FileNotFoundException e) {
10             System.out.println("Exam.test(我是catch)");  //Exam.test(我是catch)
11         }
12 
13     }

代码格式二

 1 try【进行捕获】
 2   {
 3         可能出现异常的代码
 4   }catch(异常类  对象){
 5         具体处理方法
 6   }catch(异常类  对象){    
 7         具体处理方法
 8   }finally{
 9 
10   }

示例代码

 1 public class Exam {
 2     public static void main(String[] args) {
 3         test();
 4     }
 5 
 6     public static void test() {
 7         try {
 8             InputStream inputStream = new FileInputStream("");
 9         } catch (FileNotFoundException e) {
10             System.out.println("Exam.test(我是catch)");  //Exam.test(我是catch)
11         }finally {
12             
13         }
14 
15     }
16 }

注意:catch异常的时候 一定将父类/大的的异常放在后面,精确的异常放在前面【Exception异常最大】

代码格式三

注意:catch是用于处理异常,如果没有catch就代表没有被处理过,如果该异常是检测时异常,那么必须声明

1 try【进行捕获】
2   {
3         可能出现异常的代码
4   }finally{
5 
6   }

示例代码

 1 public class FinallyDemo {
 2     private static int a;
 3     private static int b;
 4 
 5     public static void main(String[] args) {
 6         demo(4,1);
 7     }
 8 
 9     public static void demo(int a,int b) {
10 
11         try {
12             int c = a / b;
13             System.out.println(c); //4
14 
15         } finally {
16             System.out.println("我是一定执行的"); //我是一定执行的
17         }
18     }
19 }

运行机制

  try里面代码一旦有一行出现异常,try里面的代码都不会被执行,而且只会执行一个catch,不会所有的都执行

  但是try大括号后面的代码还是会继续执行【catch,finally】

 1 public class Exam {
 2     public static void main(String[] args) {
 3         testTryCatchFinally();
 4         
 5 
 6     }
 7     
 8     public static void testTryCatchFinally() {
 9         try {
10             System.out.println("ABC");   //ABC①
11             int a = 1 / 0;   //③  出现异常
12             InputStream inputStream = new FileInputStream("");
13         } catch (FileNotFoundException e) {
14             System.out.println("HelloTry.testTryCatchFinally(我是catch)");      
15         } catch (IOException e) {
16             e.printStackTrace();
17         } finally {
18             System.out.println("我是finally"); //
19         }
20     }
21 
22 }

    关键字try不能单独存在,后面必须跟catch或者finally

  顺序是 try{} [catch] [finally]

  执行的顺序是 try catch finally

对捕获的异常对象进行常见方法操作

1.String Message  //异常信息

2.String toString //异常名称:异常信息

3.printStackTrace  /*异常名称:异常信息    

           异常位置*/

注意:其实JVM默认的处理机制,就是在调用printStackTrace 方法,打印堆栈的跟踪信息

示例代码

 1 public class ExceptionDemo1 {
 2     public static void main(String[] args) {
 3         Demo demo = new Demo();
 4 
 5         try {
 6             int x = demo.demo1(4, 0);
 7             System.out.println(x);
 8         } catch (Exception e) {
 9             System.out.println(e.getMessage()); /// by zero
10             System.out.println(e.toString()); // java.lang.ArithmeticException: / by zero
11                                                
12             e.printStackTrace();
13             /*
14              * java.lang.ArithmeticException: / by zero at
15              * com.wcy.Exception.Demo.demo1(ExceptionDemo1.java:25) at
16              * com.wcy.Exception.ExceptionDemo1.main(ExceptionDemo1.java:8)
17              */
18 
19         }
20 
21     }
22 
23 }
24 
25 class Demo {
26     int demo1(int a, int b) {
27         return a / b;
28     }
29 }

对异常的声明

throws:在功能上通过throws关键字声明了该功能有可能会出现问题

注意:最后一次抛出异常,是将异常抛给虚拟机[JVM]的

示例代码

 1 public class ExceptionDemo1 {
 2     public static void main(String[] args) throws Exception {
 3         Demo demo = new Demo();
 4 
 5         int x = demo.demo1(4, 0);
 6         System.out.println(x);
 7 
 8     }
 9 
10 }
11 
12 class Demo {
13     int demo1(int a, int b)throws Exception {//在功能上通过throws关键字声明了该功能有可能会出现问题
14         return a / b;
15     }
16 }

对多异常的操作

1.在声明异常时,建议声明更为具体的异常,这样处理起来更具体

2.对方声明几个异常,就应该有几个catch块,不要定义多余的catch块

 如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面

 建议:在进行catch处理时,catch中一定要定义具体的处理方式

        不要简单的定义一句 e.printStackThrac()

        也不要简单的就书写一条输出语句 

3.异常在子父类覆盖中的体现 

 (1)子类在覆盖父类时,如果父类方法抛出异常,那么子类覆盖方法,只能抛出父类的异常或者该异常的子类

 (2)如果父类方法抛出多个异常,那么子类在覆盖方法时,只能抛出父类异常的子类

 (3)如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法是也不可以抛出异常,如果子类方法发生了异常就必须进行try...catch处理,一定不能抛

   (4)总结说明:

  在继承中,重写方法的时候,子类的异常要小于等于父类的异常

  如果子类的异常大于父类的异常那么会导致多态无法运行

  只能try抓到这个异常

  抛出异常的时候,尽量不要抛有父子关系的,如果有父子关系,直接抛出一个父类异常就可以了

示例代码

 子父类关系

  AException

  —BException

  CException

 1 public class FuziExceptionDemo {
 2     public static void main(String[] args) throws CException, AException {
 3         Demo demo = new Demo();
 4         demo.function(new Fu());
 5 
 6     }
 7 }
 8 
 9 class AException extends Exception {
10     public AException() {
11         System.out.println("我是A异常");
12     }
13 }
14 
15 class BException extends AException {
16     public BException() {
17         System.out.println("我是B异常");
18     }
19 }
20 
21 class CException extends Exception {
22     public CException() {
23         System.out.println("我是C异常");
24     }
25 }
26 
27 class Fu {
28     public void test1() throws AException {
29         throw new AException();
30     }
31 }
32 
33 class Zi extends Fu {
34     public void test2() throws CException {
35         throw new CException();
36     }
37 }
38 
39 class Demo {
40     public void function(Fu fu) throws AException {
41         try {
42             fu.test1();
43         } catch (AException e) {
44 
45         }
46         /*
47          * catch (BException e) { }
48          */
49 
50         catch (CException e) {
51 
52         }
53 
54     }
55 }

视图

finally

  特性

    1.定义一定执行的代码

      2.通常用来执行关闭资源操作

      finally的特性是无论try中的语句是否有问题,finally里的内容都会输出,只有四种情况时finally里的内容不会执行输出,当有return出现时,也是先执行finally再执行return,而且当有多个return是会输出最后面的return

示例代码

 1 public class Exam {
 2     public static void main(String[] args) {
 3         System.out.println(testReturn());
 4 
 5     }
 6     public static int testReturn() {
 7         try {
 8             System.out.println("我是try");   //我是try
 9             int a = 1 / 0;           
10             return 1;
11         } catch (Exception e) {
12             System.out.println("我是catch");  //我是catch
13             return 2;                        //2
14         } finally {
15             System.out.println("我是finally");  //我是finally
16             //            return 3;      // //3
17         }
18                //        return 4;           // // //4
19               //        System.out.println("HelloTry.testReturn(我是程序之外的代码)");
20     }
21 }

不执行finally的情况

  1)在finally语句块中发生了异常。
  2)在前面的代码中用了System.exit()退出程序。
  3)程序所在的线程死亡。
  4)关闭CPU。

            <-------抛出异常------->
              我有一辆车,车的刹车有点不好使,假如别人来借我的车,我需要把这个消息告诉他,那么他也需要注意刹车的问题

示例代码

 1 public class Exam {
 2     public static void main(String[] args) throws FileNotFoundException {
 3         test();
 4     }
 5 
 6     public static void test() throws FileNotFoundException {
 7 
 8         InputStream inputStream = new FileInputStream("");
 9     }
10 }

<---非检查异常[运行时异常][RuntimeException]--->

特性

  在Exception中有一个特殊的子类异常RuntimeException[运行时异常]

  如果在函数内抛出该异常,函数上可以不用声明,编译一样通过

  如果在函数上声明了该异常,调用者可以不用进行处理[try...catch或者throws],编译一样通过

  之所以不用在函数上声明,是因为不需要让调用者处理

  当异常发生时,希望程序停止,因为在运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修正

  自定义异常时,如果该异常的发生,无法再继续进行运算,那就让自定义异常继承RuntimeException

示例代码

 1 public class RuntimeExceptionDemo {
 2     //调用者不用处理就可以
 3 public static void main(String[] args) {
 4     Test test=new Test();
 5     test.demo(4, -1);
 6     
 7 }
 8 }
 9 
10 class ArithmeticException extends RuntimeException{
11     
12     
13     public ArithmeticException() {
14         System.out.println("出现负数异常");
15     }
16 }
17 
18 class Test{
19     public int demo(int a,int b)throws ArithmeticException  {
20         int c=a/b;
21         if (b<0) {
22             throw new ArithmeticException();
23         }
24         
25         System.out.println(c);
26         return c;
27         
28     }
29 }

视图

比较常见的运行时异常

java.lang.ArithmeticException【算术运算中,被0除或模除】

复制代码
 1 public class Exam {
 2     public static void main(String[] args) throws Exception {
 3         test();
 4     }
 5     
 6     private static void test() {
 7         int a=10;
 8         int b=0;
 9         System.out.println(a/b);
10     }
11     
12 }
复制代码

 

java.lang.NullPointerException【空指针异常

复制代码
 1 public class Exam {
 2     public static void main(String[] args) throws Exception {
 3         test();
 4     }
 5     
 6     private static void test() {
 7         String aString=null;
 8         System.out.println(aString.length());
 9     }
10     
11 }
复制代码

java.lang.ClassCastException【类转换异常】

复制代码
 1 public class Exam {
 2     public static void main(String[] args) throws Exception {
 3         
 4     }
 5     
 6     private static void test() {
 7         Student student = (Student) new Object();
 8     }
 9     
10 }
复制代码

java.lang.ArrayIndexOutOfBoundsException【数组角标越界异常

java.lang.StringIndexOutOfBoundsException【字符串角标越界异常

复制代码
 1 public class Exam {
 2     public static void main(String[] args) throws Exception {
 3         test();
 4     }
 5     
 6     private static void test() {
 7         int[] nums = new int[10];
 8         System.out.println(nums[10]);
 9     }
10     
11 }
复制代码

java.lang.NumberFormatException【数字格式异常

数字格式异常,例如提示 For input string: "1 " 提示,这就告诉我们你当前想把 "1 " 转换成数字类型时出错了

复制代码
 1 public class Exam {
 2     public static void main(String[] args) throws Exception {
 3         test();
 4     }
 5     
 6     private static void test() {
 7         String str = "10a";
 8         System.out.println(Integer.parseInt(str));
 9     }
10     
11 }
复制代码

java.lang.InputMismatchException 【输入类型不符合异常】

获取的标记与期望类型的模式不匹配,或者该标记超出期望类型的范围

示例代码

1 import java.util.Scanner;
2 
3 public class ExceptionNoclass {
4 public static void main(String[] args) {
5     System.out.println("输入一个数据");
6     Scanner scanner=new Scanner(System.in);
7     scanner.nextInt();
8 }
9 }

视图

自定义异常

  因为项目中会出现一些特有的问题,而这些问题并没有被JAVA所描述并封装对象,所以对这些特有的问题可以按照JAV对问题封装的思想,将特有的问题进行自定义的异常封装

示例代码

1 class MyselfExceptionDemo extends Exception{
2     
3 }

  当函数内部出现throw抛出异常对象,那么就必须要给对应的处理动作

  要么在内部用try...catch处理

  要么在函数上声明,让调用者处理

  一般情况下,函数内出现异常,函数上需要声明

抛出异常代码

 1 public class MyselfException {
 2     public static void main(String[] args) {
 3         TestDemo testDemo = new TestDemo();
 4         try {
 5             testDemo.test(4, -1);
 6         } catch (MyselfExceptionDemo e) {
 7             System.out.println(e.toString()); // com.wcy.Exception.MyselfExceptionDemo
 8         }
 9     }
10 }
11 
12 class MyselfExceptionDemo extends Exception {
13 
14 }
15 
16 class TestDemo {
17 
18     public int test(int a, int b) throws MyselfExceptionDemo {
19         int c = a / b;
20 
21         if (b < 0) {
22             throw new MyselfExceptionDemo(); // 抛出自定义异常
23         }
24 
25         System.out.println(c);
26         return c;
27     }
28 
29 }

无异常正常运行代码

 1 public class MyselfException {
 2     public static void main(String[] args) {
 3         TestDemo testDemo = new TestDemo();
 4         try {
 5             testDemo.test(4, 1);  //4
 6         } catch (MyselfExceptionDemo e) {
 7             System.out.println(e.toString()); 
 8         }
 9     }
10 }
11 
12 class MyselfExceptionDemo extends Exception {
13 
14 }
15 
16 class TestDemo {
17 
18     public int test(int a, int b) throws MyselfExceptionDemo {
19         int c = a / b;
20 
21         if (b < 0) {
22             throw new MyselfExceptionDemo(); // 抛出自定义异常
23         }
24 
25         System.out.println(c);
26         return c;
27     }
28 
29 } 

误区:

  打印的结果中只有异常的名称,没有异常的信息?

    因为打印的异常没有定义信息

  如何定义异常信息?

    因为父类已经把异常信息的操作完成了,所以只需要子类在构造时[构造方法/构造器],将异常信息传递给父类,用super()传递

    那么传递之后,就可以用getMessage()方法,获取自定义的异常信息了

  为什么说父类已经把异常信息定义操作都完成了?

    因为Exception继承自Throwable,在Throwable类中,早已经定义好了设定自定义异常信息的方法(Throwable(String message)),并且是构造方法。由于Exception继承自Throwable,是Throwable的一个分支,并且默认构造方法中有(Exception(String message))这个方法,自定义异常类继承自Exception,所以自定义异常类可以直接调用这个父类的构造器方法,所以在使用时只需要直接调用就可以了,方法是在构造器中用super()调用

   为什么要继承Exception?

    因为异常体系有一个特点:异常类和异常对象都被抛出,他们都具备可抛性,这个可抛性是Throwable这个体系中特有的。只有这个体系中的类和对象才可以被throws和throw操作抛出

  自定义异常可不可以继承别的类?

    自定义异常可以继承Exception也可以继承RuntimeException,但是继承Exception时一定要进行(try...catch或throws处理),继承RuntimeException[运行时异常]则不需要进行处理,这个是RuntimeException类以及其子类特有的属性

关联阅读

  构造器能不能够继承?

    不能,因为子类继承父类的时候,先运行父类构造函数;具体的说就是运行父类时就会先“调用”父类的构造函数,注意“调用”和继承不是一个含义,实质上是“自动运行”。

    简单的理解就是因为构造器得名字和类名相同所以比如说B继承A,那么A得构造器是A(),但是B得构造器是B(),所以A()不能是B得构造器

    继承(extends)的含义其实是“扩展”,子类完全没必要扩展父类的构造函数,因为反正每次调子类的时候都会“自动运行”它父类的构造函数,如果真的需要子类构造函数特殊的形式,子类直接修改或重载自己的构造函数就好了。

示例代码

 1 public class MyselfException {
 2     public static void main(String[] args) throws MyselfExceptionDemo {
 3         Test test=new Test();
 4         test.demo(4, -1);
 5     }
 6 }
 7 
 8 class MyselfExceptionDemo extends Exception{
 9     public MyselfExceptionDemo(String message) {
10         super(message);
11     }
12 }
13 
14 class Test{
15     public int demo(int a,int b) throws MyselfExceptionDemo {
16         int c=a/b;
17         if(b<0){
18             throw new MyselfExceptionDemo("出现了除数为负数额异常");//com.wcy.Exception.MyselfExceptionDemo: 出现了除数为负数额异常
19         }
20         
21         
22         return c;
23     }
24 }

  throw和throws的区别?

      1.throws使用在函数上(大括号和小括号之间)

       throw使用在函数内

      2.throws后面跟的是异常类,可以跟多个,用逗号隔开

       throw后面跟的是异常对象

示例代码

 1 class Test{                        //函数上(小括号和大括号之间)后面跟的是异常类,可以跟多个,用逗号隔开
 2     public int demo(int a,int b) throws MyselfExceptionDemo {
 3         int c=a/b;
 4         if(b<0){
 5             //函数内 后面跟的是异常对象
 6             throw new MyselfExceptionDemo("出现了除数为负数额异常");
 7         }
 8         
 9         
10         return c;
11     }
12 }
posted @ 2016-08-04 12:00  IT蓄水池  阅读(188)  评论(0)    收藏  举报