0


Java从入门到精通十(java异常)

Java从入门到精通十(java异常)

异常的引入

整理一下自己的思路,java为什么要引入异常处理机制?当然啊!因为程序运行可能会出错,在某一步骤出现问题,所以这个时候需要抛出异常,需要告诉用户是哪里是出现了问题。简单来说,这样说其实是没有问题的。但是还是没有进行严格的思考。程序运行中出现问题不一定就是异常所导致的(Exception),也有可能是错误(Error),不错,这是两个继承自Throwable类,但是其实在程序处理方面有很大的区别,所以我们区分看待。

一:异常与错误的区别

异常和错误都是在程序中可能出现的问题。但是一般我们会在程序设计中着重去处理好程序可能出现的异常。同样,我们同样在程序执行的过程中最常见的就是程序抛出的异常,比如数组越界,并发修改异常,io输入输出异常等等。我们可以发现,这些都是我们可以在事先进行好处理的,而且处理并不是很难。有时候我们为了让程序不会因为异常而断掉,我们会进行异常的处理或者说是抛出,甚至我们可以进行一个finally进行执行必须要执行的程序等等。这些我们都可以采取措施。

但是错误呢?error?很多人其实会把错误和异常进行混淆,这是程序机制上的问题,怎么能混为一谈呢?甚至有的人会说异常比错误严重,但是并不是这样。
区分的异常或者是错误不能认为是简单的语法问题。error(错误)是java程序中不可预料的异常情况,在一般情况下并不是会常常出现。如果出现了,一般是属于jvm(java虚拟机)层次方面的问题,错误导致你的java虚拟机无法正常运行,导致程序中断。这样的错误一般情况下我们是无法预先知道的,也是无法进行较好的处理的。异常我们可以进行捕捉,也就是在可以进行预知的情况下进行捕捉,进行一个预先的处理,但是错误无法捕捉。错误的出现反应了java运行系统中的内部出现的问题或者是资源耗尽。出现了这种问题,我们是很难进行处理的,一般就是让程序安全退出,别无他法。

异常类介绍

基本的这样去分类还是可以的,简单举例几个异常类
在这里插入图片描述

一: Exception及其方法说明

直接继承类就是Throwable,而Throwable是直接继承自Object的。

publicclassExceptionextends Throwable
publicclassThrowableextendsObjectimplementsSerializable

当然Exception还是有好多子类的javaapi给出了直接子类
在这里插入图片描述
javaapi给出了对该类及其子类简明的说明简明的说明

Exception 类及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件。

简单看几个构造方法

public Exception()
构造详细消息为 null 的新异常。原因尚未被初始化,可在以后通过调用 Throwable.initCause(java.lang.Throwable) 对其进行初始化。

public Exception(String message)
构造带指定详细消息的新异常。原因尚未被初始化,可在以后通过调用 Throwable.initCause(java.lang.Throwable) 对其进行初始化。

public Exception(String message,
Throwable cause)构造带指定详细消息和原因的新异常。
参数:
message - 详细消息(保存此消息,以便以后通过 Throwable.getMessage() 方法获取它)。
cause - 原因(保存此原因,以便以后通过Throwable.getCause() 方法获取它)。(允许使用 null 值,指出原因不存在或者是未知的。)
从以下版本开始:
1.4

public Exception(Throwable cause)
根据指定的原因和 (cause==null ? null : cause.toString()) 的详细消息构造新异常(它通常包含 cause 的类和详细消息)。对于那些与其他可抛出异常(例如,PrivilegedActionException)的包装器相同的异常,此构造方法很有用。
参数:
cause - 原因(保存此原因,以便以后通过Throwable.getCause() 方法获取它)。(允许使用 null 值,指出原因不存在或者是未知的。)

但是我们一般更多用到是一般的方法,具体的可以去当作功能使用的。构造方法只是在实例化的时候根据原有的功能结构来进行操作。

基本上Exception的所有一般方法都是从Throwable和Object继承过来的。

在这里插入图片描述
挑几个常用的简单说明一下

getMessage()
public String getMessage()返回此 throwable 的详细消息字符串。
返回:
此 Throwable 实例(可以为 null)的详细消息字符串。

举一个很常用的关于除法异常的例子

package exception_demo;publicclassException_1{publicstaticvoidmain(String args[]){try{div(1,0);}catch(Exception e){
           System.out.println("get message:"+e.getMessage());}}publicstaticvoiddiv(int n1,int n2){
        int result = n1/n2;
        System.out.println("result is"+result);}}

我们看到除数为0,我们预先了解到这个一定会出现问题,所以我们尝试对异常进行捕获,看看出现异常会出现什么信息。这个方法的主要作用就是输出出现的异常。

在这里插入图片描述
可以看到输出的信息,告诉我们异常的原因。

getLocalizedMessage()
public String getLocalizedMessage()创建此 throwable 的本地化描述。子类可以重写此方法,以便生成特定于语言环境的消息。对于不重写此方法的子类,默认实现返回与 getMessage() 相同的结果。

明确说明了如果不重写,那么效果和getMessage()效果是一样的。也就是说这样也是可以的,异常信息一定和getMessage()是一样的。

try{div(1,0);}catch(Exception e){
           System.out.println("get message:"+e.getLocalizedMessage());}

getCause()
public Throwable getCause()
返回此 throwable 的 cause;如果 cause 不存在或未知,则返回 null。(该 Cause 是导致抛出此 throwable 的throwable。)
此实现返回由一个需要 Throwable 的构造方法提供的 cause,或者在创建之后通过 initCause(Throwable) 方法进行设置的 cause。虽然通常不需要重写此方法,但子类可以重写它,以返回一个通过某些其他方式设置的 cause。这适用于在异常链(异常嵌套)机制被加入到 Throwable 之前存在“遗留 Throwable 链机制”的情况。注意,不必 重写任何 PrintStackTrace 方法,所有方法都调用 getCause 方法来确定 throwable 的 cause。

什么意思呢?

该方法在使用之前必须知道某段代码可能会出现什么样的异常。另外其实相比getMessage()还是多了几步。我们还可能需要实例化具体的异常类,并将需要的参数传入

我们可以这样去用,举个例子,还是那段代码段

package exception_demo;publicclassException_1{publicstaticvoidmain(String args[]){try{div(1,0);}catch(ArithmeticException e){
            System.out.println("get message:"+ e.getCause());}}publicstaticvoiddiv(int n1, int n2){try{
            int result = n1 / n2;
            System.out.println("result is"+ result);}catch(ArithmeticException e){
            ArithmeticException arithmeticException =newArithmeticException();
            arithmeticException.initCause(e);throw(arithmeticException);}}}

在这里插入图片描述
很明显这个是算数性质的异常,并将信息数输出来了。

但是其实 还是很想知道这个方法和getMessage的区别,所以我在尝试写一个可能出现异常的简单测试代码

package exception_demo;publicclassException_2{publicstaticvoidmain(String args[]){
        int[] ints ={1,2,3,4,5};try{sysdemo(ints);}catch(ArrayIndexOutOfBoundsException e){
            System.out.println(e.getCause());}}publicstaticvoidsysdemo(int arr[]){try{for(int i =0; i < arr.length; i++){
                System.out.println(arr[i]);
                System.out.println(arr[6]);}}catch(ArrayIndexOutOfBoundsException e){
            ArrayIndexOutOfBoundsException aie =newArrayIndexOutOfBoundsException();
            aie.initCause(e);throw(aie);}}}

他会把这个异常抛出来,并且异常类型也会输出
在这里插入图片描述
但是你在随便给一段越界

package exception_demo;publicclassException_o3{publicstaticvoidmain(String args[]){
        int [] arr ={1,2,3,4,5,6};try{
            System.out.println(arr[6]);}catch(Exception e){
           System.out.println(e.getMessage());}}}

在这里插入图片描述
对比两者getMessage()只输出异常的信息,就是相当于说是导致出现异常的数据。而getclause()告诉你异常的类型和异常信息。

但是一般我情愿去用getMessage(),输出信息一般也会很容易看出是哪里出现了问题。同时也有为了让程序继续执行才进行捕捉,有时候这样看来,只要能正常去处理好异常捕捉就好了。

initCause()
public Throwable initCause(Throwable cause)
将此 throwable 的 cause 初始化为指定值。(该 Cause 是导致抛出此 throwable 的throwable。)
此方法至多可以调用一次。此方法通常从构造方法中调用,或者在创建 throwable 后立即调用。如果此 throwable 通过 Throwable(Throwable) 或 Throwable(String,Throwable) 创建,此方法甚至一次也不能调用。
参数:
cause - 原因(保存此 cause,以便以后通过 getCause() 方法获取它)。(允许 null 值,指出 cause 是不存在的或是未知的。)
返回:
对此 Throwable 实例的引用。
抛出:
IllegalArgumentException - 如果 cause 是此 throwable。(throwable 不能是它自己的 cause。)
IllegalStateException - 如果此 throwable 通过 Throwable(Throwable) 或 Throwable(String,Throwable) 创建,或者此方法已经在此 throwable 上进行调用。

这个初始化方法我们在上面简单初始化过,简单说可以这样去初始化,不再赘述,这里只是简单讲一下初级的用法,具体的这里不做太过深入的探讨。

toString()
public String toString()返回此 throwable 的简短描述。结果是以下字符串的串联:
此对象的类的 name
": "(冒号和一个空格)
调用此对象 getLocalizedMessage() 方法的结果
如果 getLocalizedMessage 返回 null,则只返回类名称。
覆盖:
类 Object 中的 toString
返回:
该 throwable 的字符串表示形式。

我发现这个方法不错,你看他的字符串表达的具体形式

package exception_demo;publicclassException_o3{publicstaticvoidmain(String args[]){
        int [] arr ={1,2,3,4,5,6};try{
            System.out.println(arr[6]);}catch(Exception e){
           System.out.println(e.toString());}}}

在这里插入图片描述
确实在这方面的效果和getclause()方法的效果是一样的。

printStackTrace()
public void printStackTrace()将此 throwable 及其追踪输出至标准错误流。此方法将此 Throwable 对象的堆栈跟踪输出至错误输出流,作为字段 System.err 的值。输出的第一行包含此对象的 toString() 方法的结果。剩余行表示以前由方法 fillInStackTrace() 记录的数据。此信息的格式取决于实现,但以下示例是最常见的:
java.lang.NullPointerException
at MyClass.mash(MyClass.java:9)
at MyClass.crunch(MyClass.java:6)
at MyClass.main(MyClass.java:3)

api还说明了这个方法的一些参数,这里只要看这个方法的输出信息。

package exception_demo;publicclassException_o3{publicstaticvoidmain(String args[]){
        int [] arr ={1,2,3,4,5,6};try{
            System.out.println(arr[6]);}catch(Exception e){
           e.printStackTrace();}}}

在这里插入图片描述
看吧红色又出现了,但是其实程序出现问题抛出异常基本都会出现类似这样输出的信息的。

输出主要包括异常类型,数据源,以及出现的位置。自己需要的话,在进行异常处理的话,还是可以巧妙地去用的。

java1.8对这个方法进行划线,可能还是有点过时,但是还可以用。

但是需要注意地是这些方法绝非是对异常进行捕获输出那么简单,但是这边不做深入探究,因为在性能或者是底层源码地探究上,还有十分多地内容。我们甚至可以追溯到堆栈这戏底层地数据结构。目前还没有用到,所以就先简要介绍这些。以后遇到会继续添加内容,我们展开其它的内容。


二: 异常分类说明介绍

异常种类非常多,分类的标准也可以按照不同的方式。
在这里插入图片描述
在这里插入图片描述
但是其实终归还是分为运行时异常和非运行时异常(或者一般也说编译时异常)

运行时异常就是RuntimeException及其子类异常,比如常见的数组下标越界(IndexOutOfBoundsException),空指针异常(NullPointerException),类转换异常(ClassCastException)等。这种异常就是一般在程序编译的时候不会检查的,比如越界,编译的时候时是不会进行检查的。这种错误会出现在程序运行的过程中。
相对的编译时异常就是比如我们的io流出现的异常IOException,以及文件未被找到(FileNotFoundException),甚至还有未知服务(UnKnownHostException),io中断异常(InterruptedIOException)
这种异常类型也是很好理解,就是如果不进行处理,程序是无法运行的。

1: 运行时异常

运行时异常的直接子类就非常多
在这里插入图片描述
完整类定义

publicclassRuntimeExceptionextends Exception

还有一个简短的说明

RuntimeException 是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。
可能在执行方法期间抛出但未被捕获的 RuntimeException 的任何子类都无需在 throws 子句中进行声明。


基本的方法还是从Throwable和Object继承的

在这里插入图片描述
主要的相关方法在Excepton已经简单说明过,所以不再具体说明

RuntimeException类下常见的异常子类说明


1:ArithmeticException(算数异常类)

算数异常就是出现数学上不允许的数学问题,导致程序无法进行运行下去。

2:ArrayStoreException(数组存储异常)
一般的是存储类型不匹配

java api对此错误的说明就是

试图将错误类型的对象存储到一个对象数组时抛出的异常。例如,以下代码可生成一个 ArrayStoreException:
Object x[] = new String[3];
x[0] = new Integer(0);

3: BufferOverflowException(缓冲区越界异常)

当相关 put 操作达到目标缓冲区限制时,抛出此未经检查的异常。

4:BufferUnderflowException(缓冲区越界异常)

当相关 get 操作达到源缓冲区限制时,抛出此未经检查的异常。

5:ClassCastException(类转换异常)
这个问题会经常遇到,对象的转换的时候经常会出现这个问题

当试图将对象强制转换为不是实例的子类时,抛出该异常。例如,以下代码将生成一个 ClassCastException:
Object x = new Integer(0);
System.out.println((String)x);

6:ConcurrentModificationException(并发修改异常)

这种错误不就是并发修改的时候报的错误吗?在集合文章就说明过这种问题。对于一些集合的迭代,你不能在迭代的时候同时进行添加修改集合中的元素,这样会导致迭代器预期的迭代和实际的迭代次数不匹配,所以会导致像这样的异常。

当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。

7:EmptyStackException(栈空异常)

这个其实就是和栈相关啦!数据结构上的栈,如果你的栈是空的,那么在java中,如果你取出元素的话,比如一个peek(),它不会给你输出null,会给你抛出栈空异常

该异常由 Stack 类中的方法抛出,以表明堆栈为空

8:EnumConstantNotPresentException(枚举访问不存在异常)

当应用程序试图通过名称和枚举类型访问那些不包含具有指定名称的常量的枚举常量时,抛出该异常。

9:EventException(事件异常)

这个事件的异常一般是我们在进行事件这些操作的时候进行不规范的操作或者是部分关联出现问题的时候会抛出该异常。

事件操作可以像在其方法描述中指定的那样抛出 EventException

10:IllegalArgumentException(非法参数异常)

很简单,就比如你给一个方法的参数传递了一个它不能接收的参数,可能类型不匹配,或者是你的参数给的不正确

抛出的异常表明向方法传递了一个不合法或不正确的参数。

11:IllegalMonitorStateException(非法监视异常)

抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。

12: IllegalPathStateException(非法路径异常)(还没遇到过)

对于正在执行的特定操作而言(如将路径段追加到不具有初始 moveto 的 GeneralPath),如果操作在处于非法状态的路径上执行,则 IllegalPathStateException 表示抛出的异常。

13:IllegalStateException(非法方法调用异常)(还没遇到过)

在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。

14:IndexOutOfBoundsException(索引越界异常)

这个会发生在数组或者字符串等的排序的索引中,原因是索引超出实际范围

指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。
应用程序可以为这个类创建子类,以指示类似的异常

15:NullPointerException(空指针异常)

空指针异常,可能会发生在对象的引用区域为空,经常就是对象没有合适的初始化,导致没有明确的引用。

当应用程序试图在需要对象的地方使用 null 时,抛出该异常。这种情况包括:
调用 null 对象的实例方法。
访问或修改 null 对象的字段。
将 null 作为一个数组,获得其长度。
将 null 作为一个数组,访问或修改其时间片。
将 null 作为 Throwable 值抛出。
应用程序应该抛出该类的实例,指示其他对 null 对象的非法使用。

15:TypeNotPresentException(类型不存在异常)

当应用程序试图使用表示类型名称的字符串对类型进行访问,但无法找到带有指定名称的类型定义时,抛出该异常。此异常与 ClassNotFoundException 不同,ClassNotFoundException 是一个经过检查的异常,而此异常是未经检查的。

17:UnknownElementException(未知元素异常)

指示遇到一个未知种类的元素。如果语言有所发展并且向 Element 层次结构中添加了新种类的元素,则会发生这种情况。该异常可能由元素 visitor 抛出,指示已经为以前的语言版本创建了 visitor。

18:UnknownTypeException(未知类型异常)

指示遇到未知种类的类型。如果语言有所发展并且向 TypeMirror 层次结构中添加了新种类的类型,则会发生这种情况。该异常可能由类型 visitor 抛出,指示已经为以前的语言版本创建了 visitor。

2: 非运行时异常(编译时异常)

非运行时异常就是除了运行时异常之外的一些异常,包括IOException,SQLException以及用户自定义的一些异常也算。
这种异常时一定要事先处理的,不然编译不通过,是绝对无法运行的。我们一般采用捕获异常进行处理,或者是进行抛出给方法的调用者进行处理。

<1: 非运行时异常类常见异常类说明

<1>:IOException

当发生某种 I/O 异常时,抛出此异常。此类是失败或中断的 I/O 操作生成的异常的通用类。

这种异常一般发生在输入输出中,一般就是在字符,字节,文件,缓冲等或者进行读取,拷贝等等,一切与流相关的操作出现的异常。

IOException相关异常

1:FileLockInterruptionException(文件锁定中断异常)

当某个线程正在等待获取文件锁定时被另一个线程中断,则由该线程接收此经过检查的异常。抛出此异常之前,将设置以前被阻塞的线程的中断状态。

2: ChangedCharSetException(字符集变化异常)

ChangedCharSetException 是字符集改变时抛出的异常。

3:CharacterCodingException(字符编码异常)

出现字符编码或解码错误时,抛出此经过检查的异常。

4:ClosedChannelException(关闭禁止异常)

当试图对已关闭的、或者至少对某个 I/O 操作已关闭的信道上调用或完成该操作时,抛出此经过检查的异常。抛出此异常未必意味着该信道已完全关闭。例如,对写入操作已关闭的套接字信道,可能对读取操作仍处于打开状态。

5: FileNotFoundException(文件未知异常)

当试图打开指定路径名表示的文件失败时,抛出此异常

6:InterruptedIOException

I/O 操作已中断信号,抛出此异常。抛出 InterruptedIOException 指示输入或输出传输已经终止,原因是执行此操作的线程中断。字段 bytesTransferred 指示在发生中断之前已成功传输了多少字节。

简单列举这些,其它的一些有与传输协议相关的以及锁相关的,这里就不再列出来了。

<2>: SQLException

提供关于数据库访问错误或其他错误信息的异常。
每个 SQLException 都可提供以下多种消息:
描述错误的字符串。此字符串用作 Java Exception 消息,可以通过方法 getMessage 获得。
“SQLstate” 字符串,该字符串遵守 XOPEN SQLstate 约定或 SQL:2003 约定。SQLState 字符串的值在适当的规范中描述。DatabaseMetaData 的方法 getSQLStateType 可用于确定驱动程序返回 XOPEN 类型还是 SQL:2003 类型。
特定于每个供应商的整数错误代码。通常,这将是底层数据库返回的实际错误代码。
到下一个 Exception 的链接。可以使用此链接提供其他错误信息。
因果关系,如果存在任何导致此 SQLException 的原因。

一般就是java代码操作数据库出现的异常,需要进行处理捕获的。

常见SQLException异常举例

1:BatchUpdateException(批量更新异常)

进行批量更新操作期间发生错误时抛出的 SQLException 子类。除了 SQLException 提供的信息以外,BatchUpdateException 还提供批量更新期间成功执行的所有命令的更新计数,也就是发生错误之前执行的所有命令的更新计数。更新计数数组中元素的顺序对应于将命令添加到批处理中的顺序。
批量更新中的命令无法正确执行并抛出 BatchUpdateException 之后,驱动程序可以继续处理批处理中的剩余命令,也可以不再进行处理。如果驱动程序在失败后继续进行处理,那么批处理的每个命令在 BatchUpdateException.getUpdateCounts 方法返回的数组中都有一个对应的元素,而不仅仅是发生错误前成功执行的命令才有对应的元素。在驱动程序继续处理命令的情况下,所有执行失败的命令对应的数组元素都是 Statement.EXECUTE_FAILED。

2: RowSetWarning(一个扩展上的异常)

SQLException 的一个扩展,提供关于在 RowSet 对象上设置的数据库警告的信息。这些警告正常链接到其方法调用会导致报告警告的那些对象。此类对 SQLWarning 类进行补充。
Rowset 警告可以从 JdbcRowSet、CachedRowSetTM、WebRowSet、FilteredRowSet 或 JoinRowSet 实现中获取到。要获取在任何 RowSet 实现上报告的第一个警告,需要使用在 JdbcRowSet 接口或 CachedRowSet 接口中定义的 getRowSetWarnings 方法。要获取链接到第一个警告的警告,需要使用 RowSetWarning 方法 getNextWarning。要获取后续警告,需要对每个返回的 RowSetWarning 对象调用 getNextWarning。
继承方法 getMessage、getSQLState 和 getErrorCode 用于获取 RowSetWarning 对象中包含的信息。

3:SQLClientInfoException(客户端异常)

当无法在 Connection 上设置一个或多个客户端信息属性时,抛出此 SQLException 的子类。除了 SQLException 提供的信息外,SQLClientInfoException 还提供未设置的客户端信息属性列表。 某些数据库不允许一次设置多个客户端信息属性。对于这些数据库,即使 Connection.setClientInfo 方法抛出异常,可能也已经设置了一些客户端信息属性。应用程序可以使用 getFailedProperties 方法获取未设置的客户端信息属性列表。通过将 Map<String,ClientInfoStatus> 传递给适当的 SQLClientInfoException 构造方法来标识属性。

4: SQLNonTransientException

重试相同操作将失败(除非纠正了 SQLException 的 cause)的情况下抛出的 SQLException 子类。

5: SQLRecoverableException(恢复的异常)

应用程序执行某些恢复步骤并重试整个事务或事务分支(在分布式事务中)后,可以成功执行先前失败操作的情况下抛出的 SQLException 子类。恢复操作至少必须包括关闭当前连接和获得一个新连接。

6:SQLWarning(数据库访问异常)

提供关于数据库访问警告信息的异常。这些警告直接链接到导致报告警告的方法所在的对象。
警告可以从 Connection、Statement 和 ResultSet 对象中获得。试图在已经关闭的连接上获取警告将导致抛出异常。类似地,试图在已经关闭的语句上或已经关闭的结果集上获取警告也将导致抛出异常。注意,关闭语句时还会关闭它可能生成的结果集。

7: SyncProviderException

指示 SyncProvider 机制发生的错误。如果在从原始数源读取或向原始数据源写入时遇到冲突,则 SyncProvider 抽象类扩展将创建此异常。
SyncProvider 对象也可以创建 SyncResolver 对象,可能在构建时使用它初始化 SyncProviderException 对象,或者以后使用 SyncProvider 对象对它进行设置,如果它被实现做这些的话。
在 writer 完成冲突检查并找到一个或多个冲突之后,方法 acceptChanges 将抛出此异常。应用程序可以捕获 SyncProviderException 对象,并调用其 getSyncResolver 方法,以获取其 SyncResolver 对象。关于示例,请参阅 SyncResolver 接口注释中的代码片段。此 SyncResolver 对象将反映生成该异常的 RowSet 对象,区别在于它仅包含数据源中处于冲突状态的值。SyncResolver 对象中的所有其他值将为 null。
SyncResolver 对象可用于检查并解析一个行中的每个冲突,然后转到下一个有冲突的行,重复该过程。
SyncProviderException 对象可能包含(也可能不包含)对导致该异常条件的描述。可以调用继承的方法 getMessage,以获取该描述(如果存在)。

以上内容异常说明引用摘录自javaapi。自定义异常另起说明。

异常处理方式

一:try-catch_finally 捕获处理

我自己平时比较习惯用这种方式进行处理一些异常,格式如下

try{//捕获可能出现异常的代码块}catch(异常类型 变量){//处理异常方式}finally{//必须执行代码块}

创建一个文件输出流对象,我们当然可以在()里面写入文件路径,只是这块代码片编译器可以告诉你你所指定的路径可能会出现文件找不到的异常。

try{
          FileOutputStream fis =newFileOutputStream("");}catch(FileNotFoundException e){//e.printStackTrace();
          System.out.println(e.getMessage());}finally{//必须执行的代码块
           System.out.println("");}

文件的这个操作的异常是一定要进行处理的,不然是绝对编译不会通过的。这个是属于编译时异常的。

当然并不是说,只能进行捕获编译时异常,运行时异常照样可以进行提前的预知捕获。

空指针异常就是一个运行时异常,但是编译的时候是不会检查的。一般这个原因就是对象的引用出现问题。

你看这样写编译时不会报错的

package exception_demo;publicclassException05{private String name ="";private  int age =19;publicstaticvoidmain(String args[]){
        Exception05 ex =newException05();
        Exception05 ex01 =null;
        System.out.println(ex.age);
        System.out.println(ex01.name);}}

在这里插入图片描述
但是运行时会出现问题。所以我们可以提前对一些运行时异常进行捕获,不是说不可以。

idea的快捷键ctrl+alt+t进行快速异常代码添加

在这里插入图片描述
一定要选择对位置进行这个操作,不然就不会出现这个选项框
在这里插入图片描述

package exception_demo;publicclassException05{private String name ="";private  int age =19;publicstaticvoidmain(String args[]){
        Exception05 ex =newException05();

        Exception05 ex01 =null;try{
            ex01 =null;
            System.out.println(ex.age);
            System.out.println(ex01.name);}catch(NullPointerException e){
            e.printStackTrace();}}}

在这里插入图片描述
但是其实你需要注意的这个空指针异常

如果你用getmessage()方法获取的话,是不会得到报异常信息的,只会给你一个null。具体的可以去看源码

RuntimeException 里面的异常,
ArrayIndexOutOfBoundsException,
NullPointerException,
ClassCastException,
ArithmeticException

e.getMessage() 都是 null 。

SQLException 和 IOException 的 e.getMessage() 不为空。

但是你其实可以完全在catch下面的语句输出一个捕获到空指针异常。如果程序捕获到,那就会输出你的语句。

二:throws和throw声明抛出异常

一般需要注意两个关键字的使用
throw,throws

throw用来抛出一个指定的异常对象,这个throw一定是位于你所调用的方法体中,然后在其后面进行抛出对象

格式如下

thrownew异常类();

throw是用来直接抛出异常,当其后面的抛出的语句执行后,则继其后面的语句不再执行。程序会转向调用的程序,寻找匹配的catch语句,执行对应的catch语句,然后继续继续逐层向上,一直到最外层的异常中止,然后打印出调用栈的情况

概括就是在获取到异常时,然后将异常进行传递给调用者,将其当然的执行程序终止掉。

throws关键字其实只起到了声明的作用,或者说是标识,但是它并不是进行处理,只是让方法调用者进行处理。

throw是可以单独使用的,并不是不可以单独使用。甚至不需要结合try catch。

我们可以用它来抛出一个异常实例
你可以进行传参来告诉异常给你传递什么样的信息

package exception_demo;publicclassException06{publicstaticvoidmain(String args[]){
        
       int result =div(2,0);
       System.out.println(result);}static int div(int a,int b){if(b==0){thrownewArithmeticException("除数不能为零");}else{return a/2;}}}

在这里插入图片描述
虽然这是一个不太友好的异常处理方式,但是我只是说明throw是可以单独使用的。需要注意的是throw只能抛出一个实例。


其实很多时候会在处理异常的时候有时候感觉会用不上,但是你会感觉很多时候一些程序会用到它。这是什么用处呢?

声明一个可能出现的异常。在我们做文件操作的时候,编译器告诉你必须这样去做。文件这边的操作肯能会出现异常,如果你不进行声明异常,或者处理时不会通过的。比如这样。

在这里插入图片描述
要不你就直接捕获,要不你就声明出来,让程序自己去处理。
在这里插入图片描述
再比如写一个除法程序,你就会理解为什么为什么有时候非要进行声明或者进行捕获异常。

在这里插入图片描述

我在div方法外部进行了异常的声明,说明这个方法这里可能会出现异常,于是在主函数你调用这个方法的时候你必须进行处理,不然编译时不会通过的。

那这样就可以理解到为什么文件操作的时候我们常常会处理io的异常信息了。所以还是为了确认自己的猜测是不是正确的,所以我去看看源码。

在这里插入图片描述
摘录下来几部分

publicFileInputStream(File file) throws FileNotFoundException {
        String name =(file !=null? file.getPath():null);
        SecurityManager security = System.getSecurityManager();if(security !=null){
            security.checkRead(name);}if(name ==null){thrownewNullPointerException();}if(file.isInvalid()){thrownewFileNotFoundException("Invalid file path");}
        fd =newFileDescriptor();
        fd.attach(this);
        path = name;open(name);}//public int read() throws IOException {returnread0();}private native int read0() throws IOException;private native int readBytes(byte b[], int off, int len) throws IOException;public int read(byte b[]) throws IOException {returnreadBytes(b,0, b.length);}......

源代码里面的这些方法都是由声明异常的,throws关键字,于是你在外部调用的时候是必须进行处理的,如果你还是throws关键字,其实你还是没有处理,只是交给了jvm,但是这是完全可以的,一般情况下,我们也可以用异常捕获进行真正意义上的处理。

正如上面我们自定义的div()函数处理异常一样,我们可以这样去解决编译的问题。

package exception_demo;publicclassException06{publicstaticvoidmain(String args[]) throws Exception {

       int result =div(2,0);
       System.out.println(result);}static int div(int a,int b) throws Exception
        {return a/2;}}

当然你也可以这样操作

package exception_demo;publicclassException06{publicstaticvoidmain(String args[]){

        int result =0;try{
            result =div(2,0);}catch(Exception e){
            e.printStackTrace();}
        System.out.println(result);}static int div(int a,int b) throws Exception
        {return a/2;}}

原理上就是这样,如果你耐心看完思考。就明白throws关键字的意义所在了。

自定义异常处理

当然可以自己定义一个异常,然后进行处理,抛出你自定义的异常,但是你自定义的异常,当然还是需要继承异常类的,然后在此基础上进行操作。

我们可以自定以一个异常类继承自Exception类

package exception_demo;publicclassMyExceptionDemoextendsException{private String message;publicMyExceptionDemo(String message){super(message);//调用父类构造器this.message = message;//自定义构造方法}}

然后使用它

package exception_demo;publicclassException06{publicstaticvoidmain(String args[]){

        int result =0;try{
            result =div(2,0);
            System.out.println(result);}catch(MyExceptionDemo e){
            System.out.println(e.getMessage());//我们可以对比这三种答应方式。
          System.out.println(e.toString());
          e.printStackTrace();}}static int div(int a,int b) throws MyExceptionDemo
        {if(b ==0){thrownewMyExceptionDemo("除数不能为0");}return a/b;}}

在这里插入图片描述
e.getMessage() 还是会打印出错误原因,将我们给到的信息错误打印出来。
e.toString()会将错误类,以及错误信息打印出来
e.printStackTrace()除了两者之外还会打印出错误的位置。

为什么super()里面可以传mesage字符串信息?那就去Exception去找构造器。
在这里插入图片描述
你一去查Exception就明白为什么可以这样去传参了。

简单的就说到这样,以后如果遇到一些问题,会继续改进。欢迎指点。
jgdabc主页


本文转载自: https://blog.csdn.net/jgdabc/article/details/123028222
版权归原作者 兰舟千帆 所有, 如有侵权,请联系我们删除。

“Java从入门到精通十(java异常)”的评论:

还没有评论