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个关键字:
在这里插入图片描述

相关文章
|
22天前
|
Java 开发者
Java中的异常处理:从基础到高级
在Java编程的世界里,异常处理是一块基石,它确保了程序的健壮性和稳定性。本文将带你从异常的基础概念出发,逐步深入到高级处理技巧,通过实例展示如何在Java中有效管理和处理异常。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和技巧。
|
21天前
|
Java 程序员
Java编程中的异常处理:从基础到高级
在Java的世界中,异常处理是代码健壮性的守护神。本文将带你从异常的基本概念出发,逐步深入到高级用法,探索如何优雅地处理程序中的错误和异常情况。通过实际案例,我们将一起学习如何编写更可靠、更易于维护的Java代码。准备好了吗?让我们一起踏上这段旅程,解锁Java异常处理的秘密!
|
18天前
|
Java
Java 异常处理:11 个异常处理最佳实践
本文深入探讨了Java异常处理的最佳实践,包括早抛出晚捕获、只捕获可处理异常、不忽略异常、抛出具体异常、正确包装异常、记录或抛出异常但不同时执行、不在finally中抛出异常、避免用异常控制流程、使用模板方法减少重复代码、抛出与方法相关的异常及异常处理后清理资源等内容,旨在提升代码质量和可维护性。
|
21天前
|
安全 Java 数据库连接
Java中的异常处理:理解与实践
在Java的世界里,异常处理是维护代码健壮性的守门人。本文将带你深入理解Java的异常机制,通过直观的例子展示如何优雅地处理错误和异常。我们将从基本的try-catch结构出发,探索更复杂的finally块、自定义异常类以及throw关键字的使用。文章旨在通过深入浅出的方式,帮助你构建一个更加稳定和可靠的应用程序。
31 5
|
19天前
|
Java 程序员
深入理解Java异常处理机制
Java的异常处理是编程中的一块基石,它不仅保障了代码的健壮性,还提升了程序的可读性和可维护性。本文将深入浅出地探讨Java异常处理的核心概念、分类、处理策略以及最佳实践,旨在帮助读者建立正确的异常处理观念,提升编程效率和质量。
|
20天前
|
Java 开发者 UED
深入探索Java中的异常处理机制##
本文将带你深入了解Java语言中的异常处理机制,包括异常的分类、异常的捕获与处理、自定义异常的创建以及最佳实践。通过具体实例和代码演示,帮助你更好地理解和运用Java中的异常处理,提高程序的健壮性和可维护性。 ##
43 2
|
20天前
|
Java 开发者
Java中的异常处理机制深度剖析####
本文深入探讨了Java语言中异常处理的重要性、核心机制及其在实际编程中的应用策略,旨在帮助开发者更有效地编写健壮的代码。通过实例分析,揭示了try-catch-finally结构的最佳实践,以及如何利用自定义异常提升程序的可读性和维护性。此外,还简要介绍了Java 7引入的多异常捕获特性,为读者提供了一个全面而实用的异常处理指南。 ####
42 2
|
20天前
|
Java 开发者
Java 中的异常处理:不仅仅是 try-catch
在Java的世界里,异常处理是代码的守护神,它保护着程序不会因为意外错误而崩溃。但异常处理远不止try-catch那么简单。本文将深入探讨Java的异常处理机制,从基本的try-catch到更复杂的自定义异常和finally块的使用,带你理解如何在Java中优雅地处理错误。
50 1
|
23天前
|
Java 程序员 UED
深入理解Java中的异常处理机制
本文旨在揭示Java异常处理的奥秘,从基础概念到高级应用,逐步引导读者掌握如何优雅地管理程序中的错误。我们将探讨异常类型、捕获流程,以及如何在代码中有效利用try-catch语句。通过实例分析,我们将展示异常处理在提升代码质量方面的关键作用。
31 3
|
23天前
|
Java 数据库连接 开发者
Java中的异常处理机制:深入解析与最佳实践####
本文旨在为Java开发者提供一份关于异常处理机制的全面指南,从基础概念到高级技巧,涵盖try-catch结构、自定义异常、异常链分析以及最佳实践策略。不同于传统的摘要概述,本文将以一个实际项目案例为线索,逐步揭示如何高效地管理运行时错误,提升代码的健壮性和可维护性。通过对比常见误区与优化方案,读者将获得编写更加健壮Java应用程序的实用知识。 --- ####