网站首页 > java教程 正文
异常概述
异常也称为例外,是在程序运行过程中发生的并且会打断程序正常执行的事件,比如算术异常、空指针异常、文件找不到异常。所以在程序设计时,必须考虑到可能发生的异常事件,并做出相应的处理。这样才能保证程序可以正常运行。
Java的异常处理机制也秉承着面向对象的基本思想,在Java中,所有的异常都是以类的形式存在,除了内置的异常类之外,Java也可以自定义异常类。此外,Java的异常处理机制也允许自定义抛出异常。
为什么要使用异常
在没有异常处理的语言中,就必须使用if或switch等语句,配合所想得到的错误状况来捕捉程序里所有可能发生的错误。但为了捕捉这些错误,编写出来的代码经常有很多的if语句,有时候这样也未必能捕捉到所有的错误,而且这样做势必导致程序运行效率的降低。Java的异常处理机制恰好改进了这一点,它易于使用并且可自行定义异常类,但是不得不说,异常也是一个较为耗费性能的操作,因此我们需要合理地利用Java的异常处理机制,以增进程序的稳定性和效率。
异常的继承架构
异常可分为两大类:java.lang.Exception与java.lang.Error,这两个类均继承自java.lang.Throwable,上图为Throwable类的继承关系图。
习惯上将Error与Exception统称为异常类,但这两者本质上还是有不同的:
1、Error专门用来处理严重影响程序运行的错误,可是通常程序设计者不会涉及程序代码去捕捉这种错误,其原因在于即使捕捉到它,也无法给予适当的处理,比如Java虚拟机出错就属于一种Error
2、Exception包含了一般性的异常,这些异常通常在捕捉到之后便可以做妥善的处理,以确保程序继续运行
从继承架构图中可以看出,Exception扩展出数个子类,其中IOException、RuntimeException是较常用的两种。RuntimeException即使不编写异常处理的程序代码,依然可以编译成功,而这种异常必须是在程序运行时才有可能发生,比如数组索引值超出了范围。与RuntimeException不同的是,IOException一定要编写异常处理的程序代码才行,它通常用来处理输入/输出相关的操作,如对文件的访问、网络的连接等。
当异常发生时,发生异常的语句代码会抛出一个异常类的实例化对象,之后此对象与catch语句中的类的类型进行匹配,然后在相应的catch中进行处理。
try、catch、finally、throw、throws
当异常发生时,通常可以用两种方法来处理:
1、交由Java默认的异常处理机制做处理,但这种处理方式,Java通常只能输出异常信息,接着便终止程序的运行,比如:
1 public static void main(String[] args) throws InterruptedException 2 { 3 operateNull(null); 4 System.out.println("After operateNull"); 5 } 6 7 public static char operateNull(String str) 8 { 9 return str.charAt(0); 10 }
返回结果为:
Exception in thread "main" java.lang.NullPointerException at com.xrq.test33.TestMain.operateNull(TestMain.java:13) at com.xrq.test33.TestMain.main(TestMain.java:7)
和"接着便终止程序的运行"一致,因为第4行的语句并没有打印。
2、自行编写try-catch-finally块来捕捉异常,这种写法的最大好处是,可以灵活操控程序的流程且可做出最适当的处理,比如:
1 public static void main(String[] args) throws InterruptedException 2 { 3 try 4 { 5 Thread.sleep(1000); 6 operateNull(null); 7 } 8 catch (NullPointerException e) 9 { 10 System.out.println("NullPointerException's catch block!"); 11 throw e; 12 } 13 finally 14 { 15 System.out.println("NullPointerException's finally block!"); 16 } 17 } 18 19 public static char operateNull(String str) 20 { 21 return str.charAt(0); 22 }
返回结果为:
1 NullPointerException's catch block! 2 NullPointerException's finally block! 3 Exception in thread "main" java.lang.NullPointerException 4 at com.xrq.test33.TestMain.operateNull(TestMain.java:25) 5 at com.xrq.test33.TestMain.main(TestMain.java:10)
关于这段代码解释每个关键字:
(1)try表示要检查的程序语句
(2)catch表示异常发生时的处理语句,可省略
(3)finally表示无论catch内部写了什么,即使是return,也都会运行到的语句,可省略。finally常用于对某段待检查的代码做扫尾工作,比如ReentrantLock的unlock()、IO的close()
(4)throw表示抛出一个类的实例,注意实例二字,实例意味着throw出去的是一个实例化的异常对象。所以代码的11行也可以写为"throw new NullPointerException()",至于为什么不这么写,因为写"throw new NullPointerException()"并没有返回结果中第4行、第5行中的异常堆栈。注意,throw关键字可以写在任何地方,并不强制必须写在catch块中,运行到throw所在的行,打印异常并立即退出当前方法
(5)throws用于方法声明,表示如果方法内的程序代码可能会发生异常,且方法内又没有使用代码的代码块来捕捉这些异常时,则必须在声明方法时一并指明所有可能发生的异常,以便让调用此方法的程序得以做好准备来捕捉异常。比如"方法名称(参数...) throws 异常类1, 异常类2, 异常类3...",也可以不这么麻烦,Exception是所有异常的父类,因此也可以直接"方法名称(参数...) throws Exception"
异常场景汇总
异常细节诸多,之前我也一直有搞不清楚的地方,因此这里对多种场景做一个总结、汇总:
1、接口方法可以throws异常,但必须throws一个具体的异常,不能直接throws出去Exception
public interface InterfaceException { void ExceptionMethod() throws NullPointerException; }
2、接口方法throws异常,其实现类实现该方法的时候不强制必须抛出该异常,也可以任意抛出异常
public class InterfaceExceptionImpl implements InterfaceException { public void ExceptionMethod() { } }
public class InterfaceExceptionImpl implements InterfaceException { public void ExceptionMethod() throws ArrayIndexOutOfBoundsException { } }
3、catch块内如果捕获到了异常并且throw出去了e,那么方法之后的代码都不会再运行了;catch块内如果捕获到了异常,但是没有throw出去e,也没有任何导致程序终止的语句,那么try...catch...finally之后的语句仍然可以继续运行
4、捕获异常不可以先catch (Exception e){...}再catch (NullPointerException e)
原因是"Unreachable catch block for NullPointerException. It is already handled by the catch block for Exception",即Java检测到NullPointer这个异常是不可达的
5、方法A声明throws异常,则调用方法A的代码必须try...catch...该异常
6、方法A声明throws出Exception,调用方法A的代码必须try...catch...该异常,如果:
(1)有匹配异常的catch块,则优先走匹配异常的catch块
(2)如果没有匹配异常的catch块,但是有catch (Exception e){...},则走catch (Exception e){...}
(3)如果没有没有匹配的catch块,则调用方法A的地方throw异常,方法终止
7、如果方法中没有try...catch异常而该方法发生了异常,且方法声明中有throws,那么发生的该异常可以被抛到调用方法的代码中
8、如果方法中对某个代码块做了try...catch并且想把catch到的异常抛给调用方法的地方,那么:
(1)不可以只有throw没有throws,这将会导致捕获到的异常无法被抛给调用方法的地方
(2)不可以只有throws没有throw,这将会导致编译出错
只有在catch块中throw捕获到的异常并且在方法声明的地方throws异常,才可以将一个异常正确地抛给调用方法的地方
猜你喜欢
- 2024-11-06 Java核心知识3:异常机制详解(java的三种核心机制是什么)
- 2024-11-06 【Spring系列】05 自定义异常以及全局异常处理器 #java
- 2024-11-06 3种Sentinel自定义异常,你用过几种?
- 2024-11-06 关于Java Exception异常的深入用法及实例
- 2024-11-06 Java-throw异常详解以及过程(java throw exception)
- 2024-11-06 《JAVA编程思想》5分钟速成:第12章(异常)
- 2024-11-06 面试官:java开发中异常怎么定义好 程序员:不知道
- 2024-11-06 「译」11条Java异常处理的最佳实践
- 2024-11-06 Java入门教程十一(异常处理)(java异常处理的三种方法)
- 2024-11-06 Java,你管这叫异常?(java异常是什么意思)
你 发表评论:
欢迎- 05-16SpringBoot整合Redis实现常用功能
- 05-16基于Redis实现简单的延时消息队列
- 05-16安装Redis
- 05-16Spring系列之Redis的两种集成方式
- 05-16Django连接Redis集群问题排查思路和总结
- 05-16只需5分钟,完成Redis所有命令操作~
- 05-16熟练使用 Redis 的 5 大数据结构:Java 实战教程
- 05-16Redis 常见业务场景及实例(Java)
- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)