03JavaSE异常处理

一、 异常概念总结:

练习一:异常的体系

问题:

  1. 请描述异常的继承体系

    2.请描述你对错误(Error)的理解

    3.请描述你对异常(Expection的理解)

    4.请描述你对运行时异常(RuntimeException)的理解

    答:

  2. 异常继承体系为:异常的根类是 java.lang.Throwable,其下有两个子类:

    java.lang.Error 与 java.util.Exception 。而Exception又分为编译时期异常:checked异常,与运行时期异常:runtime异常。

  3. Error:表示不可修复的恶性的错误,只能通过修改代码规避错误的产生,通常是系统级别的,所以很严重。

    3.Exception:表示可修复的良性(相对于错误)的异常,异常产生后程序员可以并且应该通过代码的方式纠正,使程序继续运行,是必须要处理的。

    4.运行时期异常:runtime异常。在运行时期,检查异常.在编译时期,运行异常不会编译器检测(不报错)。

练习二:throw与throws的区别

问题:

  1. 请描述throw的使用位置,作用是什么?
  2. 请描述throws的使用位置,作用是什么?

    答:

  3. throw关键字通常用在方法体中,并且抛出一个异常对象。程序在执行到throw语句时立即停止,它后面的语句都不执行。

    2.throws关键字通常被应用在声明方法时,用来指定可能抛出的异常。多个异常可以使用逗号隔开。当在主函数中调用该方法时,如果发生异常,就会将异常对象抛给方法调用处。

练习三:异常的处理方式

问题:

  1. 异常处理方式有几种,分别是什么?
  2. 详细阐述每种方式对异常是如何处理的

    答:

  3. 异常的处理方式有两种,分别是使用throws和try…catch…finally

    2.throws用在方法的声明上后接异常类名,是把异常抛给调用者进行处理

    3.try…catch…finally是捕获异常,自己处理,处理完毕后面的程序可以继续运行

    a)try代码块中是可能出现异常的代码

    b)catch代码块,是遇到异常,对异常进行处理的代码

    c)finally代码块是无论是否发生异常,都必须执行的代码,用于释放资源.

练习四:常见异常,及产生原因

问题:请列举常见异常,并说明产生原因。

答:

NullPointerException:空指针异常。

当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度等等。

ArrayIndexOutOfBoundsException:数组索引越界异常。

当对数组的索引值为负数或大于等于数组大小时抛出此异常。

ArithmeticException:算术运算异常。

程序中出现了除以零这样的运算就会出这样的异常,对这种异常,大家就要好好检查一下自己程序中涉及到数学运算的地方,公式是不是有不妥了。

NumberFormatException:数字格式异常。

当试图将一个String转换为指定的数字类型,而该字符串确不满足数字类型要求的格式时,抛出该异常。

二.异常

介绍:指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。

在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象。Java处理异常的方式是中断处理

notes:

异常指的并不是语法错误,语法错误的话 编译不通过,不会产生字节码文件,根本不能运行。

①异常体系:

API:
异常机制其实就是帮助我们找到程序中的问题,

异常的根类是 

 java.lang.Throwable,下面有两个子类,

  -java.lang.Error    (工程师不能处理,只能尽量避免)

  -java.util.Exception    (由于使用不当导致,可以避免的)

平常所说的异常就是java.util.Exception

②Throwable中的常用方法:

⑴打印异常的详细信息

public void printStackTrace():

包含了异常的类型,异常的原因,还包括异常出现的位置,在开发和调试阶段,都得使用printStackTrace。
⑵获取发生异常的原因

public String getMessage():

提示给用户的时候,就提示错误原因。
⑶获取异常的类型和异常描述信息(不用)

public String toString():

③异常的分类

⑴编译时期的异常:checked异常.在编译时期,就会检查,如果没有处理异常,则编译失败(如日期格式化异常)

⑵运行时期异常:runtime异常.在运行时期,检查异常,在编译时期,运行异常不会编译器检测(不报错)(如数学异常)

三.处理异常

五大关键字:    try catch finally throw throws

①抛出异常throw

⑴格式:

throw new 异常类名(参数)

⑵抛出异常告诉调用者 :

步骤1:创建一个异常对象.封装好一些提示信息(信息可以自己编写)

 throw new NullPointerException("要访问的arr数组不存在");

步骤2:告知调用者,通过throw抛出一个异常对象,传递到调用者处,并结束当前方法的执行
例子:

     public static void main(String[] args) {
 int[] arr = {2,4,52,2};

 int index = 4;

 int element = getElement(arr, index);

 System.out.println("element = " + element);

 System.out.println("over");

}
  private static int getElement(int[] arr, int index) {

   // 判断 索引是否越界

   if (index<0||index>arr.length-1){

    // 如果越界 当执行完 throw 抛出异常随心后,方法无法继续运算

    // 这时就会结束当前方法的执行,并将异常 告知 调用者 这时就需要通过异常来解决

    throw new ArrayIndexOutOfBoundsException("数组越界");

   }

   int element = arr[index];

   return element;

  }

结果:  

 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 数组越界l~~~

 at DemoThread.ThrowTest.getElement(ThrowTest.java:22)

 at DemoThread.ThrowTest.main(ThrowTest.java:7)

②Objects非空判断

还记得我们学习过一个类Objects吗,曾经提到过它由一些静态的实用方法组成,

这些方法是null-save(空指针安全的)或null-tolerant(容忍空指针的),

那么在它的源码中,对对象为null的值进行了抛出异常操作。

public static T requireNonNull(T obj):查看指定引用对象不是null。

public static T requireNonNull(T obj) {

if (obj == null)

 throw new NullPointerException();

return obj;

}

③声明异常throws

说明:

将问题标识出来,报告给调用者,如果方法内通过throw抛出了编译时异常,而没有捕获处理,那么必须同throws进行声明

让调用者去处理.

关键字throws运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常

格式:

修饰符 返回值类型 方法名(参数) throws 异常类名1 ,异常类名2...{}

例子:

   public static void main(String[] args) throws FileNotFoundException {

 read("a.txt");

}

// 如果定义功能时 有问题 发生需要报告给调用者,可以通过在方法上使用throws关键字进行声明

public static void read(String path) throws FileNotFoundException{

 if (!path.equals("a.txt")){

  // 假设 如果不是a.txt认为 该文件不存在 是一个错误 也就是异常 throw

  throw new FileNotFoundException("文件不存在");

 }

}

④捕获异常try catch

捕获异常:

Java中对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式处理

格式:

try{
// 编写可能出现异常的代码
}catch(异常类型 e){
处理异常的代码
// 可以是记录日志、打印异常信息、继续抛出异常
}



try:该代码块中编写可能产生的异常代码

catch:用来进行某种异常的捕获,实现对捕获到的异常进行处理

例子:

  public static void main(String[] args) {

try {
 read("a12.txt");

}catch (FileNotFoundException e){

 // 打印异常

 e.printStackTrace();

}

System.out.println("over");
}

private static void read(String path) throws FileNotFoundException {

 if (!path.equals("a.txt")){

  throw new FileNotFoundException("文件不存在");

 }

  /* if (!path.equals("a.txt")){

  throw new IOException();

  }*/

}

捕获的异常常用的方法:

Throwable类中定义了一些查看方法:
  • public String getMessage():获取异常的描述信息,原因(提示给用户的时候,就提示错误原因。
  • public String toString():获取异常的类型和异常描述信息(不用)。
  • public void printStackTrace():打印异常的跟踪栈信息并输出到控制台。

    包含了异常的类型,异常的原因,还包括异常出现的位置,在开发和调试阶段,都得使用printStackTrace。
    
    在开发中呢也可以在catch将编译期异常转换成运行期异常处理。
    

    多个异常使用捕获又该如何处理呢?

  1. 多个异常分别处理。
  2. 多个异常一次捕获,多次处理。
  3. 多个异常一次捕获一次处理。

    一般我们是使用一次捕获多次处理方式,

    格式如下:

    try{

      编写可能会出现异常的代码
    
    }catch(异常类型A e){ 当try中出现A类型异常,就用该catch来捕获.
    
      处理异常的代码
    
      //记录日志/打印异常信息/继续抛出异常
    
    }catch(异常类型B e){ 当try中出现B类型异常,就用该catch来捕获.
    
      处理异常的代码
    
      //记录日志/打印异常信息/继续抛出异常
    
    }
    

    notes:

    注意:这种异常处理方式,要求多个catch中的异常不能相同,

    并且若catch中的多个异常之间有子父类异常的关系,

    那么子类异常要求在上面的catch处理,

    父类异常在下面的catch处理

⑤finally代码块

说明:

有一些特定的代码无论异常是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些语句执行不到。

而finally就是解决这个问题的,在finally代码块中存放的代码都是一定会被执行的。

打开一些物理资源(比如磁盘文件/网络链接/数据库链接等)我们都得在使用完之后,最终关闭打开的资源

用法:

try catch finally:自身需要处理异常,最终还得关闭资源。



notes: 

 finally不能单独使用。

例子:

   public static void main(String[] args) {

 try {

  read("a11.txt");

 }catch (FileNotFoundException e){

  e.printStackTrace();

 }finally {

  System.out.println("不管怎么样我都要执行");

 }

 System.out.println("over");

}

private static void read(String path) throws FileNotFoundException {

 if (!path.equals("a.txt")){

  throw new FileNotFoundException("文件不存在!");

 }

}

tips:

只有在try或者catch中调用退出JVM的相关方法时,此时finally才不会执行,否则finally用远会执行



 结果:

  不管怎么样我都要执行

  java.io.FileNotFoundException: 文件不存在!

  over

   at DemoThread.finallyTest01.read(finallyTest01.java:19)

   at DemoThread.finallyTest01.main(finallyTest01.java:8)

⑥异常注意事项

⑴运行时期异常被 抛出可以不处理,既不捕获也不声明抛出

⑵如果父类抛出多个异常,子类覆盖父类方法时,只能抛出相同的异常或者他的子集

⑶父类方法没有抛出异常,子类覆盖父类该方法时也不可抛出异常,此时子类产生该异常,只能捕获处理,不能声明抛出

⑷当多异常处理时,捕获处理,前边的类不能时后边类的父类

⑸当try/catch后可以主机finally代码块,其中的代码一定会被执行,通常用于资源回收

⑹如果finally有return语句,永远返回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
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  说明: 

   为什么需要自定义异常类:

    Java中不同的异常类,分别表示着某一种具体的异常情况,那么在开发中总是有些异常情况是SUN没有定义好的,此时我们根据自己业务的异常情况来定义异常类。,例如年龄负数问题,考试成绩负数问题。

    在上述代码中,发现这些异常都是JDK内部定义好的,但是实际开发中也会出现很多异常,这些异常很可能在JDK中没有定义过,例如年龄负数问题,考试成绩负数问题.那么能不能自己定义异常呢?

    什么是自定义异常类:

    在开发中根据自己业务的异常情况来定义异常类.

    自定义一个业务逻辑异常: LoginException。一个登陆异常类。

   异常类如何定义:

    1. 自定义一个编译期异常: 自定义类 并继承于java.lang.Exception。

    2. 自定义一个运行时期的异常类:自定义类 并继承于java.lang.RuntimeException

  例子: 

   public class DiyETest {

    private static String[] names= {"bill","hill","jill"};

    public static void main(String[] args) {

     // 模拟登录

     try{

      // 可能出现异常的代码

      checkUsername("bill");

      // 如果没有就是注册成功

      System.out.println("注册成功");

     }catch (LoginException e){

      e.printStackTrace();

     }

    }

    private static boolean checkUsername(String uname) throws LoginException {

     for (String name:names){

      if (name.equals(uname)){

       // 如果名字在其中 则抛出 登录异常

       throw new LoginException("禁止登录");

      }

     }

     return true;

    }

   }

 
   class LoginException extends Exception{

    public LoginException() {

    }

    /**

     *

     * @param name 表示异常提示

     */

    public LoginException(String name){

     super(name);

    }

   }

Powered by Hexo and Hexo-theme-hiker

Copyright © 2016 - 2018 Francis的个人博客 All Rights Reserved.

UV : | PV :