Java异常处理详解(全文干货,写得非常全,值得收藏)

简介: Java异常处理详解(全文干货,写得非常全,值得收藏)

一.初识Java异常

  1. 对异常的理解:异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。(开发过程中的语法错误和逻辑错误不是异常)
  2. Java程序在执行过程中所发生对异常事件可分为两类:
  • Error:Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:StackOverflowError和OOM。一般不编写针对性 的代码进行处理。
  • Exception: 其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:
    • 空指针访问
    • 试图读取不存在的文件
    • 网络连接中断
    • 数组角标越界
  1. 运行时异常和编译时异常
  • 运行时异常

    • 是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该积极避免其出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常。
    • 对于这类异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。
  • 编译时异常

    • 是指编译器要求必须处置的异常。即程序在运行时由于外界因素造成的一 般性异常。编译器要求Java程序必须捕获或声明所有编译时异常。
    • 对于这类异常,如果程序不处理,可能会带来意想不到的结果。

在这里插入图片描述


二.Error和Exception

1.Error

代码示例一:java.lang.OutOfMemoryError(堆溢出)

public class ErrorTest {
    
    public static void main(String[] args) {
    
        //堆溢出:java.lang.OutOfMemoryError
        Long[] arr = new Long[1024*1024*1024];
    }
}

运行结果:
在这里插入图片描述

代码示例二:java.lang.StackOverflowError(栈溢出)

public class ErrorTest {
     
    public static void main(String[] args) {
     

        //栈溢出:java.lang.StackOverflowError
        main(args);
    }
}

运行结果:
在这里插入图片描述

2.Exception(运行时异常和编译时异常)

运行时异常
    /* ******************以下是运行时异常****************** */
    //ArithmeticException
    @Test
    public void test1(){
      
        int num1 = 3;
        int num2 = 0;
        int num3 = 3 / 0;
    }

    //InputMismatchException
    @Test
    public void test2(){
      
        Scanner scanner = new Scanner(System.in);
        int i = scanner.nextInt();
        System.out.println(i);
        scanner.close();
    }

    //NumberFormatException
    @Test
    public void test3(){
      
        String str = "abcd";
        int num = Integer.parseInt(str);
    }

    //ClassCastException
    @Test
    public void test4(){
      
        Object obj = new Boolean(true);
        String str = (String)obj;
    }

    //IndexOutOfBoundsException
    @Test
    public void test5(){
      
        ArrayIndexOutOfBoundsException
        Byte[] bytes = new Byte[3];
        System.out.println(bytes[4]);
    }

    //NullPointerException
    @Test
    public void test6(){
      
        int[] arr = null;
        System.out.println(arr[1]);
    }

编译时异常
/* ******************以下是编译时异常****************** */
    @Test
    public void test7(){
       
        File file = new File("a.txt");
        //java.io.FileNotFoundException
        FileInputStream fis = new FileInputStream(file);
        //java.io.IOException
        int date = fis.read();
        while (date != -1){
       
            System.out.println((char)date);
            date = fis.read();
        }

        fis.close();
    }

ps:对于编译时异常,我们需要异常处理

三.异常处理:抓抛模型

1.抓抛解释

过程一:“抛”:程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象, 并将此对象抛出;一旦抛出对象以后,其后的代码就不再执行。
关于异常对象的产生:
① 系统自动生成的异常对象
② 手动的生成一个异常对象,并抛出(throw)过程二:“抓”:可以理解为异常的处理方式:① try-catch-finally ② throws

2.try-catch-finally的使用

try{undefined
//可能出现异常的代码

}catch(异常类型1 变量名1){undefined
//处理异常的方式1
}catch(异常类型2 变量名2){undefined
//处理异常的方式2
}catch(异常类型3 变量名3){undefined
//处理异常的方式3
}

finally{undefined
//一定会执行的代码
}

说明:

finally是可选的。使用try将可能会出现异常的代码段包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。一旦处理完成,就跳出当前的
try-catch结构(在没有写finally的情况)。继续执行其后的代码catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓。
catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则,报错常用的异常对象处理的方式: ① String getMessage() ② printStackTrace()在try结构中声明的变量,再出了try结构以后,就不能再被调用try-catch-finally结构可以嵌套finally中声明的是一定会被执行的代码。即使catch中又出现异常了,try中有return语句,catch中有return语句等情况。像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中。

示例一:

@Test
public void test1(){
        
    String str = "abcd";
    int num = 1314;
    try {
        
        num = Integer.parseInt(str);

        System.out.println("进入try代码块!");
    }catch (NumberFormatException e){
        
        System.out.println("出现数值转换异常了!");
        System.out.println(e.getMessage());
        e.printStackTrace();
        System.out.println("该catch语句块将要执行完了!");
    } catch (NullPointerException e){
        
        System.out.println("出现空指针异常!");
    } catch (Exception e){
        
        System.out.println("出现异常了");
    }finally {
        
        System.out.println("执行finally语句了!");
    }
    System.out.println(num);
}

输出结果:

在这里插入图片描述

示例二:

 @Test public void test2(){
          File file = new File("a.txt"); FileInputStream fis = null; try {
          fis = new FileInputStream(file); int date = fis.read(); while(date != -1){
          System.out.println((char)date); date = fis.read(); } } catch (FileNotFoundException e) {
          e.printStackTrace(); }catch (IOException e){
          e.printStackTrace(); }finally {
          System.out.println("执行finally语句了!"); try {
          fis.close(); } catch (IOException e) {
          e.printStackTrace(); } } } 

输出结果:
在这里插入图片描述

总结:

使用try-catch-finally处理编译时异常,是得程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。

开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。针对于编译时异常,我们说一定要考虑异常的处理。

3.throws + 异常类型的使用

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

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

子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型(子类重写的方法也可以不抛出异常)

public class SuperClass {
           public void method() throws IOException {
           } } class SubClass extends SuperClass{
           //报错,子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型 // public void method() throws Exception{
           // // } public void method() throws FileNotFoundException{
           } } 
开发中如何选择使用try-catch-finally 还是使用throws? 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果
子类重写的方法中有异常,必须使用try-catch-finally方式处理。执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法使用throws
的方式进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理。

代码示例:

public class ErrorThrows {
            public static void method1() throws IOException {
            File file = new File("a.txt"); FileInputStream fileInputStream = new FileInputStream(file); int data = fileInputStream.read(); while(data != -1){
            System.out.println((char)data); data = fileInputStream.read(); } fileInputStream.close(); } public static void method2() throws IOException {
            method1(); } public static void method3() throws IOException {
            method1(); } public static void main(String[] args) {
            try {
            method3(); } catch (IOException e) {
            e.printStackTrace(); } } } 

4.手动抛出一个异常类对象(throw关键字使用)

代码示例:

public class ReturnException {
             static void method1(){
             try{
             System.out.println("进入方法1"); throw new RuntimeException("手动抛出异常"); }catch (Exception e){
             e.printStackTrace(); System.out.println(e.getMessage()); } finally {
             System.out.println("执行finally语句了!"); } } public static void main(String[] args) {
             method1(); } } 

输出结果:
在这里插入图片描述

四.自定义异常类

自定义异常类,有如下三步骤:

继承于现有的异常结构:RuntimeException 、Exception提供全局常量:serialVersionUID提供重载的构造器

自定义异常类:

public class MyExceptionClass extends Exception{
              static final long serialVersionUID = -5641210210148784L; public MyExceptionClass() {
              } public MyExceptionClass(String message) {
              super(message); } } 

手动抛出上述自定义的异常类对象:

public class MyExceptionTest {
               static void method1() throws MyExceptionClass {
               Scanner scanner = new Scanner(System.in); System.out.println("请输入大于0的数据:"); double next = scanner.nextDouble(); if(next >0){
               System.out.println("您输入的数据为:"+next); }else {
               throw new MyExceptionClass("您输入的数据不满足要求!"); } } public static void main(String[] args) {
               try {
               method1(); } catch (MyExceptionClass myExceptionClass) {
               myExceptionClass.printStackTrace(); } } } 

运行结果:
在这里插入图片描述

目录
相关文章
|
5天前
|
Java
在 Java 中捕获和处理自定义异常的代码示例
本文提供了一个 Java 代码示例,展示了如何捕获和处理自定义异常。通过创建自定义异常类并使用 try-catch 语句,可以更灵活地处理程序中的错误情况。
|
5天前
|
Java
在 Java 中,如何自定义`NumberFormatException`异常
在Java中,自定义`NumberFormatException`异常可以通过继承`IllegalArgumentException`类并重写其构造方法来实现。自定义异常类可以添加额外的错误信息或行为,以便更精确地处理特定的数字格式转换错误。
|
9天前
|
Java 编译器
探索Java中的异常处理机制
【10月更文挑战第35天】在Java的世界中,异常是程序运行过程中不可避免的一部分。本文将通过通俗易懂的语言和生动的比喻,带你了解Java中的异常处理机制,包括异常的类型、如何捕获和处理异常,以及如何在代码中有效地利用异常处理来提升程序的健壮性。让我们一起走进Java的异常世界,学习如何优雅地面对和解决问题吧!
|
6天前
|
IDE 前端开发 Java
怎样避免 Java 中的 NoSuchFieldError 异常
在Java中避免NoSuchFieldError异常的关键在于确保类路径下没有不同版本的类文件冲突,避免反射时使用不存在的字段,以及确保所有依赖库版本兼容。编译和运行时使用的类版本应保持一致。
|
8天前
|
Java 编译器
如何避免在 Java 中出现 NoSuchElementException 异常
在Java中,`NoSuchElementException`通常发生在使用迭代器、枚举或流等遍历集合时,尝试访问不存在的元素。为了避免该异常,可以在访问前检查是否有下一个元素(如使用`hasNext()`方法),或者使用`Optional`类处理可能为空的情况。正确管理集合边界和条件判断是关键。
|
9天前
|
Java 开发者
Java中的异常处理:从基础到高级
【10月更文挑战第35天】在Java的世界里,异常处理是维护程序健壮性的关键。本文将深入浅出地探讨Java的异常处理机制,从基本的try-catch语句到自定义异常类的实现,带领读者理解并掌握如何在Java中优雅地处理错误和异常。我们将通过实际代码示例,展示如何捕获、处理以及预防潜在的运行时错误,确保程序即使在面临意外情况时也能保持稳定运行。
25 7
|
8天前
|
Java 数据库连接 开发者
Java中的异常处理机制及其最佳实践####
在本文中,我们将探讨Java编程语言中的异常处理机制。通过深入分析try-catch语句、throws关键字以及自定义异常的创建与使用,我们旨在揭示如何有效地管理和响应程序运行中的错误和异常情况。此外,本文还将讨论一些最佳实践,以帮助开发者编写更加健壮和易于维护的代码。 ####
|
12天前
|
Java
Java 异常处理下篇:11 个异常处理最佳实践
本文深入探讨了 Java 异常处理的最佳实践,包括早抛出晚捕获、只捕获可处理的异常、不要忽略捕获的异常、抛出具体检查性异常、正确包装自定义异常、记录或抛出异常但不同时执行、避免在 `finally` 块中抛出异常、避免使用异常进行流程控制、使用模板方法处理重复的 `try-catch`、尽量只抛出与方法相关的异常以及异常处理后清理资源。通过遵循这些实践,可以提高代码的健壮性和可维护性。
|
11天前
|
Java
Java异常捕捉处理和错误处理
Java异常捕捉处理和错误处理
12 1
|
12天前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
29 2