Java基础-异常篇

1-认识异常

1.1-什么是异常?

​ 异常,在Java程序中指的是:因程序问题而中断程序执行的现象。java

1.2-异常分类

 
异常体系

​ 在Java中,为了维护程序正常执行,Java提供了处理异常的异常机制(异常类)。数据库

​ 在Java提供的异常机制中,其中java.lang.Throwable是根类,而根类的派生类有java.lang.Error和java.lang.Excepiton两个子类。编程

​ Error,错误(绝症),该类型异常在程序中没法处理,只能尽可能避免。数组

​ Excepiton,编译期异常(写源代码时)(小毛病,好比:相似感冒),该类型异常在程序中是可处理的。Excepiton类型还有一个子类RunTimeException,表示运行期异常(程序运行的过程当中),该类型异常在程序中也是可处理的。网络

​ 为了更好的区分以上描述的异常分类,咱们看如下程序。ui

// 【Error异常】 // Exception in thread "main" java.lang.OutOfMemoryError: Java heap space // 内存溢出。超出了分配给JVM内存大小。 // 该程序只能修改源代码解决问题。 int[]nums = new int[1024*1024*1024]; // 【Exception异常】 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); // Unhandled exception: java.text.ParseException // 此处在编写源代码时就发生异常,该异常后续能够经过相关的处理机制处理和避免 Date date = format.parse("2083-10-10"); // 【RunTimeException异常】 int[] nums = {1,2,3}; // Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException // 在程序运行时出现的异常,数组下标超出。该异常能够经过相关异常机制处理 System.out.println(nums[4]);

1.3-异常产生的过程

在编程中,为了更好的处理异常,咱们首先要了解异常产生的过程。下面经过一段异常代码来分析。spa

  • 代码:调试

    // 需求:定义一个方法,用来获取指定数组的指定位置的元素 public static void main(String[] args) { int[]nums = {1,2,3}; System.out.println(getElement(nums,4)); } public static int getElement(int[]arr,int index){ return arr[index]; }
  • 分析:日志

    1. 在执行getElement方法的过程当中,JVM检测出数组索引越界异常,此时JVM会作两件事:
      • 建立一个ArrayIndexOutOfBoundsException异常对象,该对象中包含了异常的信息(内容、缘由、位置)
      • 由于getElment方法中没有异常处理,JVM会把异常对象抛给getElment方法的调用处-main方法。
    2. main方法接收到了ArrayIndexOutOfBoundsException异常对象,也没有处理异常,则会把异常对象抛给JVM
    3. JVM接收到了main方法后,会作两件事:
      • 在控制台打印异常信息(内容、缘由、位置)
      • 终止程序的执行。
  • 图解:code

     
    异常产生的流程

     

2-处理异常

2.1 关键字

异常相关的关键字有:

  • try
  • catch
  • finally
  • throw
  • throws

2.2 抛出异常-throw

  • 做用:在指定的方法内部抛出异常。

  • 格式:throw new xxxException(参数)

    • 参数是字符串格式,用来描述异常。
  • 注意事项:

    1. throw关键字必须写在方法内部。
    2. throw关键字后建立的对象必须是Exception或Exception的子类对象。
    3. throw关键字抛出的异常对象,咱们必须处理异常对象。
      • throw关键字抛出的时RunTimeException或RunTimeException子类异常对象时,咱们能够不处理,由于JVM会默认处理(打印异常信息、中断程序)。
      • throw关键字抛出的时编译期异常时(编写源代码时),咱们必须处理(能够经过throws或try-catch的方式处理)
  • 代码:

    public static void main(String[] args) { int[]nums = {1,2,3}; // getElement(nums,4); // 异常:java.lang.ArrayIndexOutOfBoundsException: 索引越界:4 int[]nums2=null; getElement(nums2,0); // 异常java.lang.NullPointerException: 传入的数组对象为null } public static int getElement(int[]arr,int index){ if(arr==null){ throw new NullPointerException("传入的数组对象为null"); } if(index<0||index>=arr.length){ throw new ArrayIndexOutOfBoundsException("索引越界:" + index); } return arr[index]; }

2.3 Objects非空判断

​ Objects中提供了一个方法,能够检测一个对象为null并抛出异常,咱们来应用一下,并查看其源代码更好的理解throw关键字的应用。

  • 方法名称:public static <T> T requireNonNull(T obj):查看指定引用对象不是null。

  • 源代码:

    public static <T> T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; }
  • 应用:

    public static void main(String[] args) { int[]nums = {1,2,3}; // getElement(nums,4); // 异常:java.lang.ArrayIndexOutOfBoundsException: 索引越界:4 int[]nums2=null; getElement(nums2,0); // 异常java.lang.NullPointerException } public static int getElement(int[]arr,int index){ Objects.requireNonNull(arr); // 应用 if(index<0||index>=arr.length){ throw new ArrayIndexOutOfBoundsException("索引越界:" + index); } return arr[index]; }

2.4 声明异常-throws

当程序抛出一个异常对象给调用者时,调用者必需要处理异常,此时能够选择throws关键字来处理。

throws关键字的做用就是把异常对象继续抛给其余调用者,若其余调用者没有处理异常,则最终会抛给JVM来处理。

  • 格式:

    /* 修饰符 返回值类型 方法名() throws XXX1Exception,XXX2Exception... { throw new XXX1Exception("产生的缘由"); throw new XXX2Exception("产生的缘由"); } */
  • 注意事项:

    1. throws关键字必须写在方法声明出。
    2. throws关键字后声明的异常必须是Exception或Exception子类异常。
    3. 方法内部抛出多个异常时,那么throws关键字后必须声明多个异常。
      • 若是抛出的多个异常之间存在继承关系,那么直接抛出父类便可。
    4. 调用了一个声明异常的方法,调用者必须处理该异常,处理方式有:
      • 调用者继续声明throws抛给其余调用者。最终抛给JVM。
      • 在调用者内部经过try-catch处理异常。
  • 代码

    // 需求:定义一个读取文件的方法,检测文件的路径和后缀名 public static void main(String[] args) throws Exception { retFile("a.txt"); } // 读取文件的方法 // private static void retFile(String path) throws FileNotFoundException,IOException { private static void retFile(String path) throws IOException { // 若是后缀名不是.txt则抛出 if(!path.contains(".txt")){ throw new FileNotFoundException("文件后缀名不是.txt"); } if(path.contains("c:")) { throw new IOException("文件路径错误"); } }

2.5 捕获处理异常-(try-catch)

throws声明异常的弊端是:异常后续代码没法执行(由于交给了JVM,JVM会终止程序)。

try-catch可让调用者处理异常,并会继续执行后续程序。

  • 格式

    try { // 可能会发生异常的程序 // 若发生异常,try会检测到异常对象 }catch(异常类型 变量) { // catch会接收到异常对象,能够在此代码块中进行处理 }catch(异常类型 变量) { // catch会接收到异常对象,能够在此代码块中进行处理 }...
  • throwable中经常使用的异常方法

    • public String getMessage() :获取异常的描述信息,缘由(提示给用户的时候,就提示错误缘由。
    • public String toString() :获取异常的类型和异常描述信息(不用)。
    • public void printStackTrace() :打印异常的跟踪栈信息并输出到控制台。
      • 包含了异常的类型,异常的缘由,还包括异常出现的位置,在开发和调试阶段,都得使用printStackTrace。
  • 代码

    // 需求:定义一个读取文件的方法,检测文件的路径和后缀名 public static void main(String[] args) { try{ retFile("d.txt"); }catch (Exception e) { e.printStackTrace(); } System.out.println("后续代码"); /* 执行结果: java.io.IOException: 文件路径错误 at it.leilei.cn.demo01.Main01.retFile(Main01.java:27) at it.leilei.cn.demo01.Main01.main(Main01.java:12) 后续代码 */ } // 读取文件的方法 private static void retFile(String path) throws IOException { // 若是后缀名不是.txt则抛出 if(!path.contains(".txt")){ throw new FileNotFoundException("文件后缀名不是.txt"); } if(!path.contains("c:")) { throw new IOException("文件路径错误"); } }

2.6 finally代码块

  • finally关键字的做用:有一些特定的代码不管异常是否发生,都须要执行。另外,由于异常会引起程序跳转,致使有些语句执行 不到。而finally就是解决这个问题的,在finally代码块中存放的代码都是必定会被执行的。

  • finally使用格式:try...catch...finally自身须要处理异常,最终还得关闭资源。

  • finally关键字的应用场景:当咱们在try语句块中打开了一些物理资源(磁盘文件/网络链接/数据库链接等),咱们都得在使用完以后,最终关闭打开的资源。

  • 代码:

    // 需求:定义一个读取文件的方法,检测文件的路径和后缀名 public static void main(String[] args) { try{ retFile("d.txt"); }catch (Exception e) { e.printStackTrace(); }finally { System.out.println("释放资源"); } System.out.println("后续代码"); } // 读取文件的方法 private static void retFile(String path) throws IOException { // 若是后缀名不是.txt则抛出 if(!path.contains(".txt")){ throw new FileNotFoundException("文件后缀名不是.txt"); } if(!path.contains("c:")) { throw new IOException("文件路径错误"); } }

2.7 异常处理注意事项

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

    1. 多个异常分别处理。
    2. 多个异常一次捕获,屡次处理。
    3. 多个异常一次捕获一次处理
  • 通常咱们是使用一次捕获屡次处理方式,格式以下:

    • 格式:

      try{ 编写可能会出现异常的代码 }catch(异常类型A e){ 当try中出现A类型异常,就用该catch来捕获. 处理异常的代码 //记录日志/打印异常信息/继续抛出异常 }catch(异常类型B e){ 当try中出现B类型异常,就用该catch来捕获. 处理异常的代码 //记录日志/打印异常信息/继续抛出异常 }
    • 注意:这种异常处理方式,要求多个catch中的异常不能相同,而且若catch中的多个异常之间有子父类异

      常的关系,那么子类异常要求在上面的catch处理,父类异常在下面的catch处理。

  • 运行时异常被抛出能够不处理。即不捕获也不声明抛出(JVM默认会进行处理)。

  • 若是finally有return语句,永远返回finally中的结果,避免该状况.

    public static void main(String[] args) { int num = getNum(); System.out.println(num); // 100 } // 读取文件的方法 public static int getNum() { int a = 10; try { return a; }catch (Exception e){} finally { a = 100; return a; } }
  • 若是父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异 常。

    class Fu{ // 若是父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异 常。 public void show1() throws IndexOutOfBoundsException{}; } class Zi extends Fu{ // 子类重写父类方法时,抛出和父类相同的异常 // public void show1() throws IndexOutOfBoundsException{}; // 或者是父类异常的子类ArrayIndexOutOfBoundsException 继承 IndexOutOfBoundsException // public void show1() throws ArrayIndexOutOfBoundsException{}; // 不抛出异常 public void show1() {}; }

3-自定义异常类

3.1 为何要自定义异常类?

​ 咱们说了Java中不一样的异常类,分别表示着某一种具体的异常状况,那么在开发中老是有些异常状况是SUN没有定义好的,此时咱们根据本身业务的异常状况来定义异常类。例如年龄负数问题,考试成绩负数问题等等。

3.2 什么是自定义异常类?

​ 在开发中根据本身业务的异常状况来定义异常类.

​ 自定义一个业务逻辑异常: RegisterException。一个注册异常类。

3.3 如何定义异常类

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

3.4 代码

要求:咱们模拟注册操做,若是用户名已存在,则抛出异常并提示:亲,该用户名已经被注册。

public static void main(String[] args) { // 接收用户注册的用户名 String name = new Scanner(System.in).next(); try{ check(name); }catch (RegisterException e){ e.printStackTrace(); return; } System.out.println("注册成功"); } public static void check(String n) throws RegisterException{ String[]users={"张三","李四","王五"}; for (int i = 0; i < users.length; i++) { if (n.equals( users[i])) { throw new RegisterException("亲,该用户名已经注册"); } } }
public class RegisterException extends Exception{ public RegisterException(){ super(); } public RegisterException(String message){ super(message); } }
相关文章
相关标签/搜索