Java学习笔记(十三):异常处理

简介: Java学习笔记(十三):异常处理

@[toc]
  
  
  

  

异常概述与异常体系结构

  

  

异常概述

  

异常: 在Java语言中,将程序执行中发生的不正常情况称为 “异常” 。
(开发过程中的语法错误和逻辑错误不是异常)

  

Java程序在执行过程中所发生的异常事件可分为两类:

  • Error(错误) :Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:StackOverflowError(栈溢出) 和 OOM(堆溢出) 。一般不编写针对性的代码处理 Error
// 栈溢出:java.lang.StackOverflowError
main(args);        // main方法递归 自己调用自己

// 堆溢出:java.lang.OutOfMemoryError
Integer[] arr = new Integer[1024*1024*1024];
  • Exception(异常) :其他因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:空指针访问、试图读取不存在的文件、网络连接中断、数组角标越界 ...

  

Error 和 Exception 的区别:
Error 通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机(JVM)一般会选择终止线程; Exception 通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常。

  

对于 Exception 错误,一般有两种解决办法:

  1. 遇到错误就终止程序的运行。
  2. 由程序员在编写程序时,就考虑到错误的检测,错误消息的提示,以及错误的处理。

  
捕获错误最理想的是在编译期间,但有的错误只有在运行时才会发生。
比如: 除数为0,数组下标越界等

  
Exception 又分为:

  • 编译时异常

    1. Exception类中了 RuntimeException类及其子类的其他类都是编译时异常。

      1. 程序在运行时由于外界因素造成的一般性异常。编译器要求Java程序必须捕获或声明所有编译时异常。
      2. 对于这类异常,必须进行处理,否则程序无法通过编译。
  • 运行时异常

    1. Exception类中的 `RuntimeException 类及其子类`都是运行时异常。
    2. 一般是指编程时的逻辑错误,是程序员应该积极避免其出现的异常。
    3. 对于这类异常,`可以不作处理`,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。
    

  

  

异常体系结构

  

在这里插入图片描述

  

所有异常类型都是内置类 Throwable 的子类,因而 Throwable 在异常类的层次结构的顶层。

接下来 Throwable 分成了两个不同的分支。一个分支是Error,它表示不希望被程序捕获或者是程序无法处理的错误;另一个分支是Exception,它表示用户程序可能捕捉的异常情况或者说是程序可以处理的异常。

  

  

// ******************以下是编译时异常***************************
    File file = new File("hello.txt");
    FileInputStream fis = new FileInputStream(file);    // 报错:FileNotFoundException
        
    int data = fis.read();    // 报错:IOException
    while(data != -1){
        System.out.print((char)data);
        data = fis.read();    // 报错:IOException
    }
    
    fis.close();    // 报错:IOException


// ******************以下是运行时异常***************************

// ArithmeticException:算数运算异常
    int a = 10;
    int b = 0;
    int c = a / b;    // 除0了,运行错

// InputMismatchException:输入不匹配异常,即输入的值数据类型与设置的值数据类型不能匹配
    Scanner scanner = new Scanner(System.in);
    int score = scanner.nextInt();
    System.out.println(score);

    scanner.close();

// NumberFormatException:数字格式化异常
    String str = "123";
    str = "abc";
    int num = Integer.parseInt(str);    // abc不能转为数字


// ClassCaseException:类型转换异常
    Object obj = new Date();
    String str = (String)obj;    // 两不相关的类之间不能类型转换


// ArrayIndexOutOfBoundsException:数组下标越界异常
public void test2() {
    int[] arr = new int[10];
    System.out.println(arr[10]);

    String str = "abc";
    System.out.println(str.charAt(3));


// NullPointerException:空指针异常
    int[] arr = null;
    System.out.println(arr[3]);

    String str = "abc";
    str = null;
    System.out.println(str.charAt(0));

  
  
  

  

异常的处理 —— 抓抛模型

  

  
过程一:抛

程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象,并将此对象抛出。
一旦对象抛出后,其后的代码都不再执行。
  

关于异常对象的产生:

  1. 系统自动生成的异常对象
  2. 手动生成一个异常对象,并抛出(throw)。

  
过程二:抓

可以理解为异常的处理方式:

  1. try - catch - finally
  2. throw

  
  
  

  

异常处理机制一:try-catch-finally

  

  

基本结构:

try {
    // 可能出现异常的代码
} catch(异常类型1 e) {
    // 处理异常的方式
} catch(异常类型2 e) {
    // 处理异常的方式
} catch(异常类型3 e) {
    //处理异常的方式
}
...
finally {
    // 一定会执行的代码
}

  

说明:

  1. finally是可选的。根据需求判断到底写不写。
  2. 使用 try 把可能出现异常的代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去 catch 中进行匹配。
  3. 一旦 try 中的异常对象匹配到某一个 catch 时,就进入 catch 中进行异常处理。一旦处理完成,就跳出当前的 try - catch 结构(在没写finally的情况下)。继续执行后续代码。
  4. catch 中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓;

catch 中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则就会报错!即,先子类,后父类。

  1. 常用的异常对象处理方式:

getMessage() :获取异常信息,返回值是字符串(必须sout打印才能显示)。
printStackTrace() :获取异常类名和 异常信息(所以它包含了getMessage的内容),以及异常出现在程序中的位置。返回值是void(直接调用就显示)。

  1. 在 try 结构中声明的变量,在出了 try 结构后,就不能在被调用了;如果想在外面调用,就把变量声明在 try 结构外,然后在 try 中赋值。
  2. try-catch-finally 结构可以嵌套。

  

体会:

  1. 使用 try-catch-finally 处理编译时异常,只能保证程序在编译时不再报错,但是运行时仍可能报错。相当于使用 try-catch-finally 将一个编译时可能出现的异常,延迟到运行时出现。
  2. 由于运行时异常比较常见,所以通常就不对运行时异常编写 try-catch-finally 了。只是对于编译时异常才一定要考虑异常处理。

  

  

finally的使用:

  

  1. finally 是可选的。根据需求判断到底写不写。
  2. finally 中声明的是一定会被执行的代码。即使 catch 中又出现异常了。
  3. 如果 try 或 catch 中有 return,当执行到 return 时,不会立即跳出方法,而是先执行 finally 中的语句,再跳出方法。
  4. 像数据库连接、输入输出流、网络编程socket等资源,JVM是不能自动回收的,需要自己手动的进行资源的释放。此时的资源释放,就需要声明再 finally 中。

  
  
  

  

异常处理机制二:throws + 异常类型

  

  
如果一个方法可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。

  
throws + 异常类型 写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。
一旦方法体执行时出现了异常,就会在异常代码处生成一个异常类的对象,此对象满足 throws 后异常类型时,就会被抛出。异常代码后续的代码就不再执行!

  
在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。

  

体会:

  • try-catch-finally:真正的将异常处理掉了。
  • throws:只是将异常抛给了方法的调用者。并没有真正将异常处理掉。

  
  
  

  

方法重写时,抛出异常类型的规则

  

子类重写的方法抛出的异常类型 不大于 父类被重写的方法抛出的异常类型。

  

如何选择使用 try-catch-finally 还是使用 throws:

  1. 如果父类中被重写的方法没有 throws 方式处理异常,则子类重写的方法也不能使用 throws,意味着如果子类重写的方法中有异常,必须使用 try-catch-finally 方式处理。
  2. 执行的方法a中,先后又调用了另外的几个方法,且这几个方法是递进关系执行的。推荐使用 throws 方式处理这几个方法。而执行的方法a可以考虑使用 try-catch-finally 方式处理。

  
  
  

  

手动抛出异常

  

Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出,也可根据需要使用人工创建并抛出。

  

步骤:

  1. 首先要生成异常类对象
  2. 然后通过 throw 语句实现抛出操作(提交给Java运行环境)
// 结构
throw new 异常类();


// 举例:
throw new Exception("数据有误!");

  
  
  

  

自定义异常类

  

  • 一般地,自定义异常类都是 RuntimeException的子类。
  • 自定义异常类通常需要编写几个重载的构造器。
  • 自定义异常需要提供 serialVersionUID。
  • 自定义的异常通过throw抛出。
  • 自定义异常最重要的是异常类的名字,当异常出现时,可以根据名字判断异常类型。

  

如何自定义异常类?

  1. 继承于现有的异常结构:RuntimeException、Exception 。
  2. 提供全局常量:serialVersionUID ,每个自定义异常类的全局常量都不一样。
// 这是源码里的Exception,自定义时需要改下面的值
static final long serialVersionUID = -3387516993124229948L;
  1. 提供重载的构造器。

  
  
  

  

异常处理总结

  
异常处理5个关键字:
在这里插入图片描述

相关文章
|
8天前
|
存储 安全 Java
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(进阶篇)
本文是Java基础的进阶篇,对异常、集合、泛型、Java8新特性、I/O流等知识进行深入浅出的介绍,并附有对应的代码示例,重要的地方带有对性能、底层原理、源码的剖析。适合Java初学者。
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(进阶篇)
|
2天前
|
Java 程序员 开发者
Java中的异常处理:深入理解try-catch-finally语句
【9月更文挑战第18天】在Java编程中,异常处理是确保程序健壮性和可靠性的关键组成部分。本文将深入探讨Java的异常处理机制,特别是try-catch-finally语句的使用和重要性。通过实际代码示例,我们将展示如何捕获和处理异常,以及如何在finally块中执行必要的清理操作。无论你是初学者还是有经验的开发者,这篇文章都将帮助你更好地理解和应用Java的异常处理。
14 6
|
4天前
|
安全 Java 开发者
Java中的异常处理:从基础到高级
【9月更文挑战第16天】在Java的世界里,异常处理是代码的守护神,它确保了程序的健壮性和稳定性。本文将带你深入理解Java异常处理的机制,从简单的try-catch块到复杂的自定义异常和finally语句的使用。我们将通过实际代码示例探索如何有效地捕获和处理异常,以及如何设计异常安全的应用。无论你是Java新手还是有经验的开发者,这篇文章都将提供有价值的见解和技巧,帮助你提升代码质量和编程技能。
17 8
|
1天前
|
Java 开发者 UED
深入理解Java异常处理机制
【9月更文挑战第19天】在Java编程的世界里,异常处理是一块基石,它确保了程序的健壮性和可靠性。本文将深入浅出地探讨Java异常处理的核心概念,包括异常的类型、如何捕获和处理异常以及自定义异常的使用。通过具体代码示例,我们将展示如何在Java中有效地管理和利用异常处理机制,以确保你的程序即使在面对不可预见的错误时也能优雅地运行。
|
2天前
|
Java 程序员 数据库连接
Java编程中的异常处理:从基础到进阶
【9月更文挑战第18天】在Java的世界里,异常处理是每个程序员必须面对的挑战。本文将带你从异常的基本概念出发,通过实际的代码示例,深入探讨如何有效地管理和处理异常。我们将一起学习如何使用try-catch块来捕捉异常,理解finally块的重要性,以及如何自定义异常类来满足特定需求。无论你是初学者还是有经验的开发者,这篇文章都将为你提供新的见解和技巧,让你的Java代码更加健壮和可靠。
|
2天前
|
Java 数据库连接 UED
掌握Java编程中的异常处理
【9月更文挑战第18天】在Java的世界中,异常是那些不请自来的客人,它们可能在任何时候突然造访。本文将带你走进Java的异常处理机制,学习如何优雅地应对这些突如其来的“访客”。从基本的try-catch语句到更复杂的自定义异常,我们将一步步深入,确保你能够在面对异常时,不仅能够从容应对,还能从中学到宝贵的经验。让我们一起探索如何在Java代码中实现健壮的异常处理策略,保证程序的稳定运行。
|
4天前
|
Java 程序员 开发者
Java中的异常处理机制深度解析
本文旨在深入探讨Java中异常处理的核心概念与实际应用,通过剖析异常的本质、分类、捕获及处理方法,揭示其在程序设计中的关键作用。不同于常规摘要,本文将直接切入主题,以简明扼要的方式概述异常处理的重要性及其在Java编程中的应用策略,引导读者快速把握异常处理的精髓。
|
3天前
|
Java 程序员 UED
掌握Java中的异常处理:从基础到进阶
【9月更文挑战第17天】在Java的世界里,异常处理是每个程序员必须精通的技能。就像驾驶一艘船穿越变幻莫测的海洋,了解如何应对风暴(异常)是确保航行顺利的关键。本文将引导你从理解异常的本质开始,逐步深入到高级处理技巧,让你的代码更加健壮和可靠。准备好,让我们启航,探索Java异常处理的奥秘!
16 4
|
6天前
|
Java 开发者
Java中的异常处理机制
本文将深入探讨Java中异常处理的基本概念和机制,包括try-catch-finally块、throws关键字以及自定义异常类的使用方法。我们将通过实例演示如何在Java程序中有效地捕获和处理异常,确保程序的健壮性和稳定性。无论您是Java编程的初学者还是有一定经验的开发者,本文都能为您提供有价值的参考。
|
4天前
|
Java 编译器 开发者
Java中的异常处理机制:从基础到高级应用
在Java编程中,异常处理是一个至关重要的部分,它帮助开发者处理运行时错误,确保程序的鲁棒性和可靠性。本文将深入探讨Java异常处理的基础和高级应用,包括异常的分类、捕获和处理方法,以及如何使用自定义异常和异常链。通过实际案例,我们将展示如何有效利用Java的异常处理机制来提升代码质量。