首页 > 其他分享 >异常

异常

时间:2024-08-05 15:17:50浏览次数:13  
标签:Exception 抛出 捕获 try catch 异常

异常

1.什么是异常

在Java中,异常(Exception)是指程序执行过程中可能出现的不正常情况或错误。它是一个事件,会干扰程序的正常执行流程,并可能导致程序出现错误或崩溃。异常在Java中是以对象的形式表示的,这些对象是从java.lang.Throwable类或其子类派生而来。

定义:异常是在程序执行期间发生的事件,它中断正在执行的程序的正常指令流。为了能够及时有效地处理程序中的运行错误,Java专门引入了异常类。

2.Java异常类结构图

Java异常类结构是Java语言异常处理框架的基础,它允许程序在遇到预期或意外情况时,能够优雅地处理这些错误,而不是立即终止运行。Java异常类结构的核心是java.lang.Throwable类,它是所有异常和错误的根类。

Throwable类及其子类

  • Throwable:所有异常和错误的超类。它有两个直接子类:ErrorException

Error类

  • Error:表示程序无法恢复的严重错误,如系统崩溃、内存溢出等。这类错误通常不需要程序处理,因为它们通常是不可控的系统级错误。常见的Error子类包括OutOfMemoryErrorStackOverflowError等。

Exception类

  • Exception:表示程序本身可以处理的异常。它进一步分为两大类:运行时异常(Unchecked Exception)和非运行时异常(Checked Exception,也称为编译时异常)。

3.Exception分类

3.1.运行时异常

  • 运行时异常(RuntimeException及其子类):在程序运行时可能发生的异常,这些异常通常是由于程序中的逻辑错误导致的,而不是由外部因素(如文件不存在、网络问题等)引起的。Java编译器不要求程序必须显式地处理这些异常,但开发者仍然应该尽力避免它们的发生,以提高程序的健壮性和可靠性。

    常见的运行时异常:

    1. NullPointerException(空指针异常):
      • 当尝试访问或操作一个未初始化(即为null)的对象时抛出。
      • 常见场景包括调用null对象的属性或方法。
    2. ArrayIndexOutOfBoundsException(数组索引越界异常):
      • 当尝试访问数组的索引超出其有效范围时抛出。
      • 例如,访问数组的负索引或超出数组长度的索引。
    3. ArithmeticException(算术异常):
      • 在进行算术运算时,如果违反了运算规则(如整数除零),则抛出此异常。
    4. ClassCastException(类型转换异常):
      • 当尝试将对象强制转换为不是其实例的子类时抛出。
      • 例如,将String对象转换为Integer类型。
    5. IllegalArgumentException(非法参数异常):
      • 当向方法传递了非法或不适当的参数时抛出。
      • 例如,向方法传递了负数的数组长度。
    6. IllegalStateException(非法状态异常):
      • 当对象的状态不允许进行某些操作时抛出。
      • 例如,在已经关闭的流上调用读写方法。
    7. UnsupportedOperationException(不支持的操作异常):
      • 当尝试调用对象上不支持的方法时抛出。
      • 例如,在不可修改的集合上调用修改方法。
    8. ConcurrentModificationException(并发修改异常):
      • 在多线程环境下,当某个线程在遍历集合的同时,另一个线程修改了该集合,导致遍历抛出此异常。
    9. NumberFormatException(数字格式异常):
      • 当尝试将字符串转换为数字时,如果字符串的格式不正确,则抛出此异常。
      • 例如,将非数字的字符串转换为整数。
    10. SecurityException(安全异常):
      • 当安全管理器存在且其checkPermission方法不允许进行某些操作时抛出。

3.2.受检查异常

  • 受检查异常(Checked Exception):受检查异常是指在编译时期就需要程序员进行处理的异常。这些异常通常是由外部因素引起的,如文件操作、数据库连接等,它们的发生是可以预见的,并且程序应该提供相应的处理逻辑来应对。这类异常在编译时必须显式处理,即要么在方法内部使用try-catch语句捕获并处理,要么在方法签名上通过throws关键字声明可能会抛出的异常。常见的非运行时异常包括IOExceptionSQLException等。

    常见的受检查异常类:

    1. IOException:输入输出异常,表示在输入输出过程中发生的错误。这是最常见的受检查异常之一,几乎所有的文件读写、网络通信等操作都可能抛出这个异常。
    2. SQLException:SQL异常,表示数据库操作中发生的错误。例如,执行SQL语句时语法错误、连接数据库失败等。
    3. ClassNotFoundException:类未找到异常,当尝试加载一个类但找不到其定义时抛出。这通常发生在动态加载类时,如使用Class.forName()方法。
    4. FileNotFoundException:文件未找到异常,当试图打开一个不存在的文件时抛出。这个异常是IOException的子类,但它特别用于表示文件未找到的情况。
    5. EOFException:文件结束异常,当输入流到达文件末尾且没有更多数据可读时抛出。这也是IOException的一个子类。

4.异常处理机制

4.1.抛出异常(Throwing Exceptions)

在Java中,可以通过throw关键字来显式地抛出一个异常。throw后面跟的是一个异常对象,这个对象必须是Throwable或其子类的实例。通常,我们会抛出Exception或其子类的实例,以表示程序中的异常情况。

示例

public class TestThrow {  
    public static void main(String[] args) {  
        try {  
            throw new Exception("这是一个自定义的异常信息");  
        } catch (Exception e) {  
            System.out.println(e.getMessage());  
        }  
    }  
}

在这个示例中,main方法内部通过throw关键字抛出了一个Exception对象,这个对象包含了字符串"这是一个自定义的异常信息"作为异常信息。然后,这个异常被try块包围,并由紧随其后的catch块捕获。在catch块中,我们打印出了异常的信息。

4.2.捕获异常

在Java中,捕获异常是通过try-catch语句来实现的。try块用于包裹可能抛出异常的代码,而catch块则用于捕获并处理这些异常。如果try块中的代码抛出了异常,并且这个异常与某个catch块中声明的异常类型相匹配,那么控制流就会跳转到该catch块,并执行其中的代码。

基本的try-catch结构

try {  
    // 尝试执行的代码,可能会抛出异常  
} catch (ExceptionType1 e1) {  
    // 处理ExceptionType1类型的异常  
} catch (ExceptionType2 e2) {  
    // 处理ExceptionType2类型的异常  
    // 可以有多个catch块来处理不同类型的异常  
} finally {  
    // 可选的finally块,无论是否发生异常都会执行  
    // 通常用于释放资源,如关闭文件、数据库连接等  
}

示例

public class TryCatchExample {  
    public static void main(String[] args) {  
        try {  
            int result = 10 / 0; // 这行代码会抛出ArithmeticException  
        } catch (ArithmeticException e) {  
            System.out.println("发生了算术异常: " + e.getMessage());  
        } finally {  
            System.out.println("finally块总是会被执行");  
        }  
  
        try {  
            String text = null;  
            int length = text.length(); // 这行代码会抛出NullPointerException  
        } catch (NullPointerException e) {  
            System.out.println("发生了空指针异常: " + e.getMessage());  
        }  
  
        // 注意:如果没有异常被抛出,catch块将不会被执行  
        try {  
            System.out.println("这条语句不会抛出异常");  
        } catch (Exception e) {  
            // 这里的代码不会被执行,因为没有异常被抛出  
        }  
    }  
}

捕获多种类型的异常

你可以通过添加多个catch块来捕获不同类型的异常。catch块的顺序很重要,因为一旦某个catch块匹配了抛出的异常,后续的catch块就不会再被检查。因此,你应该先捕获最具体的异常,然后再捕获更一般的异常(如Exception)。

捕获所有类型的异常

虽然不推荐这样做(因为它会隐藏错误),但你可以通过捕获Exception类(所有异常类的超类)来捕获所有类型的受检查和非受检查异常。

try {  
    // 尝试执行的代码  
} catch (Exception e) {  
    // 处理所有类型的异常  
}

然而,请注意,RuntimeException及其子类(非受检查异常)通常不需要显式捕获,因为Java编译器不要求你处理它们。但是,如果你确实想捕获并处理它们,你可以像上面那样做。

注意事项

  • finally块是可选的,但如果你使用了它,无论是否发生异常,它都会被执行。这对于清理资源特别有用。
  • 如果在try块或catch块中使用了returnbreakcontinue语句,并且存在finally块,那么finally块会在这些语句执行之前执行。但是,finally块中的return语句会覆盖trycatch块中的return语句(如果有的话)。
  • 尽量避免在finally块中抛出异常,因为这可能会掩盖原始异常。如果确实需要在finally块中执行可能抛出异常的代码,请确保你能够妥善处理这些异常,或者至少将它们记录到日志中。

4.3.异常传播

在Java中,异常传播(Exception Propagation)是指当一个方法内部发生异常时,这个异常可以被抛出到调用该方法的代码中,进而可以继续向上传播,直到被捕获或程序终止。异常传播是Java异常处理机制的一个重要方面,它允许开发者在更高的层次上处理异常,从而避免在每个可能抛出异常的代码块中都进行异常处理。

异常传播的基本规则

  1. 抛出异常:当一个方法内部发生异常时,可以使用throw关键字抛出异常。如果这个方法没有捕获这个异常,那么它就会沿着调用栈向上传播。
  2. 捕获异常:在异常传播的路径上,如果某个方法使用try-catch语句捕获了异常,那么异常就不会继续向上传播。捕获异常后,可以在catch块中处理异常,或者再次抛出异常(可以使用throw关键字,或者通过throw new Exception(...)抛出一个新的异常)。
  3. 声明抛出异常:如果一个方法可能抛出受检查异常(checked exception),但是该方法内部并没有捕获这个异常,那么这个方法就必须在方法签名上使用throws关键字声明这个异常。这样,调用这个方法的代码就必须处理这个异常,要么通过try-catch语句捕获,要么继续向上抛出。
  4. 异常传播直到被捕获:异常会一直沿着调用栈向上传播,直到被某个try-catch语句捕获,或者直到到达程序的顶层(通常是main方法或线程的入口点),此时如果没有被捕获,JVM会打印出异常的堆栈跟踪信息,并终止程序。

示例

public class ExceptionPropagationExample {  
  
    public static void main(String[] args) {  
        try {  
            method1();  
        } catch (Exception e) {  
            System.out.println("在main方法中捕获了异常: " + e.getMessage());  
        }  
    }  
  
    public static void method1() throws Exception {  
        method2();  
    }  
  
    public static void method2() throws Exception {  
        try {  
            // 假设这里有一些可能抛出异常的代码  
            throw new Exception("这是一个异常");  
        } catch (Exception e) {  
            // 在这里处理异常,或者重新抛出  
            // 这里我们选择重新抛出异常  
            throw e; // 异常继续向上传播  
        }  
    }  
}

在这个示例中,method2内部抛出了一个异常,由于method2catch块中使用了throw e;,这个异常被重新抛出。然后,这个异常沿着调用栈向上传播到method1,但是method1并没有捕获这个异常,而是使用throws关键字声明了它。因此,这个异常继续向上传播到main方法,并在那里被捕获和处理。

注意事项

  • 合理地使用异常传播可以使代码更加清晰和易于维护,但是过度使用或滥用异常传播(如将异常用于控制程序流程)可能会导致代码难以理解和调试。
  • 在设计API时,应该仔细考虑哪些异常是应该被声明为受检查异常(checked exception),哪些应该是非受检查异常(unchecked exception,即RuntimeException及其子类)。受检查异常要求调用者显式地处理异常,这有助于编写更健壮的代码;但是,如果过多地使用受检查异常,可能会使API的使用变得繁琐。

5.自定义异常

在Java中,自定义异常是通过继承Java的异常类(如ExceptionRuntimeException及其子类)来实现的。自定义异常允许你定义具有特定含义的异常,这些异常可以更好地反映你的应用程序中可能发生的错误情况。

继承Exception

当你想要创建一个受检查的异常(checked exception)时,应该继承Exception类。受检查的异常是那些在编译时要求被捕获或声明的异常。

public class MyCustomException extends Exception {  
    // 构造函数  
    public MyCustomException() {  
        super(); // 调用父类的无参构造函数  
    }  
  
    public MyCustomException(String message) {  
        super(message); // 调用父类的带有详细信息的构造函数  
    }  
  
    // 可以根据需要添加更多的构造函数和方法  
}

继承RuntimeException

当你想要创建一个非受检查的异常(unchecked exception)时,应该继承RuntimeException类或其子类。非受检查的异常不需要在方法签名中声明,也不需要被强制捕获。

public class MyRuntimeException extends RuntimeException {  
    // 构造函数  
    public MyRuntimeException() {  
        super(); // 调用父类的无参构造函数  
    }  
  
    public MyRuntimeException(String message) {  
        super(message); // 调用父类的带有详细信息的构造函数  
    }  
  
    // 可以根据需要添加更多的构造函数和方法  
}

使用自定义异常

一旦你定义了自定义异常,就可以在代码中像使用Java标准异常那样使用它们了。例如,你可以在方法内部抛出自定义异常,或者在捕获到异常时抛出自定义异常来封装原始异常。

抛出自定义异常

public void doSomething() throws MyCustomException {  
    // 一些逻辑  
    if (/* 某种错误条件 */) {  
        throw new MyCustomException("发生了自定义异常");  
    }  
}

捕获并处理自定义异常

try {  
    doSomething();  
} catch (MyCustomException e) {  
    // 处理异常  
    System.out.println("捕获到自定义异常: " + e.getMessage());  
}

标签:Exception,抛出,捕获,try,catch,异常
From: https://www.cnblogs.com/tubby233/p/18343278

相关文章

  • 服务异常,报too many open files
    "toomanyopenfiles"错误表示进程打开的文件句柄数量超出了操作系统允许的最大限制。解决方法:临时增加限制:可以使用命令 ulimit-n<数量> 来临时提升当前shell会话中的打开文件数量限制。永久增加限制:编辑 /etc/security/limits.conf 文件,添加或修改相应的行来......
  • seaweedfs-csi-driver 运行异常:volume hasn't been staged yet
     Defaultedcontainer"csi-seaweedfs-plugin"outof:csi-seaweedfs-plugin,driver-registrar,csi-liveness-probeI080109:12:04.188240main.go:73willrunnode:true,controller:false,attacher:trueI080109:12:04.188817main.go:79connectto......
  • 异常处理及其相关知识点
    写代码的时候,对于那些不确定会报什么错误或者说感觉可能会报错的地方,才会用到异常处理。但是切记,一般情况下不要用,毕竟这玩意影响代码的可读性,毕竟是你写代码的时候附加的逻辑。正本清源很多人以为只有try..except这种代码逻辑才是异常处理,我只能说大傻逼,懂个锤子。难道if........
  • Java - 异常与File
    异常灵魂四问:如果try中没有遇到问题,怎么执行?try全部执行,catch不执行如果try中可能会遇到多个问题,怎么执行?写多个catch与之对应,父类异常需要写在下面如果try中遇到的问题没有被捕获,怎么执行?异常会默认交给虚拟机处理,try...catch白写如果try中遇到了问题,那......
  • Python函数的异常
    #异常:是一个事件,这个时间在程序执行过程中发生,影响了程序的正常执行#异常处理最终目的:让程序在有异常时,仍能够正常运行#语法格式一:try:  print(a)  #可能够引发异常的现象的代码except:  #基类异常  print('出现错误')b=10print(b)#法二try: ......
  • java如何避免NullPointerException(空指针异常,NPE)
    本文将简单的介绍nep以及如何避免npe1.npe简介空指针异常(NullPointerException)意思是指java中的异常类。当应用程序试图在需要对象的地方使用null时,抛出该异常。这种情况包括:调用null对象的实例方法。访问或修改null对象的字段。将null作为一个数组,获得其长度......
  • Oracle归档日志异常增长问题的排查过程 转载 : https://blog.csdn.net/3moods/article
    Oracle归档日志是Oracle数据库的重要功能,用于将数据库的重做日志文件(RedoLog)保存到归档日志文件(ArchiveLog)中。归档日志的作用是提供数据库的备份和恢复功能,以及支持数据库的持续性和数据完整性。当数据库处于归档模式时,数据库引擎会将已经写满的重做日志文件保存到归档日志文件......
  • 【Linux应急响应—下 】一文解明Linux应急响应(hw蓝队兄弟看这里):主机资源异常如何排查?C
    Linux应急响应重要声明linux应急响应各项资源异常CPU排查内存网络带宽网络连接关闭进程Linux系统日志排查登入验证日志登入失败次数登入成功统计攻击者IP个数攻击次数排列,由高到低中间件日志nginxapachetomcat分析维度:上篇文章在此处:【Linux应急响应—上】一文......
  • 2008-2022年 上市公司-异常审计费用(初始数据,计算代码,参考文献和最终数据)
    异常审计费用指的是实际审计费用与正常审计费用之间的偏差部分,这种偏差可能由多种不可观测因素引起,包括审计师的额外努力、审计师与被审计单位之间的特殊关系,或是被审计单位在市场中的优势地位等。研究异常审计费用与审计质量的关系,对于理解审计市场运作和提高审计透明度具有重......
  • 在处理用户输入时,当捕获到异常后,需要适当的清理输入流,以确保程序可以正确继续执行
    问题描述代码示例publicclassExample{publicstaticvoidmain(String[]args){Scannerscanner=newScanner(System.in);while(true){System.out.print("正常输入一个数字:");intanInt=scanner.nextInt();//正常......