欢迎关注专栏《Java架构筑基》——专注于Java技术的研究与分享!

Java架构筑基​zhuanlan.zhihu.com

  • Java架构筑基——专注于Java技术的研究与分享!
  • 后续文章将首发此专栏!
  • 欢迎各位Java工程师朋友投稿和关注
  • # 链接 Java程序员福利"常用资料分享"

异常是运行时在代码序列中引起的非正常状态。在不支持异常处理的计算机语言中,必须手动检查和处理错误,Java语言则采用面向对象的方式管理运行时错误

一、基础知识

Java异常是用来描述在一段代码中发生的异常情况的对象。当出现引起异常的情况时,就会创建用来表示异常的对象,并在引起异常的方法中抛出异常对象。方法可以选择自己处理异常或者传递异常交由其他方法来处理

Java异常处理通过五个关键字进行管理:try、catch、throw、throws、finally

在try代码快中封装可能发生异常的程序语句,对这些语句进行监视。如果在try代码块中发生异常,就会将异常抛出。代码使用catch来捕获异常,并可以定义一些方法来处理异常。系统生成的异常由Java运行时系统自动抛出。为了手动抛出异常,需要使用throw关键字。从方法中抛出的任何异常都必须通过一条throws子句进行指定。在try代码块结束之后必须执行的所有代码则需要放在finally代码块中

二、异常类型

所有异常类型都是内置类Throwable的子类,Throwable的两个子类将异常分为两个不同的分支。一个分支是Exception类,这个类既可以用于用户程序当前捕获的异常情况,也可以用于创建自定义异常类型的子类。另一个分支是Error类,该类定义了在常规环境下不希望由程序捕获的异常。Error类型的异常由Java运行时系统使用,以指示运行时系统本身发生了某些错误

三、未捕获的异常

没有被程序捕获的所有异常,最终都会交由Java运行时系统提供的默认处理程序捕获。默认处理程序会显示一个描述异常的字符串,输出异常发生的堆栈踪迹并终止程序

例如,运行如下代码:

public class Demo {public static void main(String[] args) {int a=2/0;}}

生成的异常信息:

Exception in thread "main" java.lang.ArithmeticException: / by zeroat Demo.main(Demo.java:5)

抛出的异常的类型是Exception的子类ArithmeticException,即算术异常,更具体地描述了发生的错误类型。Java提供了一些能与可能产生的各种运行时错误相匹配的内置异常类型

四、使用try和catch

进行主动的异常处理有两个优点:第一,语序允许修复错误;第二,阻止程序自动终止

为了主动处理运行时错误,可以在try代码块中封装希望监视的代码,之后通过catch子句指定希望捕获的异常类型。 例如,参照如下代码:

    public static void main(String[] args) {try{int a=10/0;System.out.println("输出语句1");}catch(ArithmeticException e){System.out.println("输出语句2");}System.out.println("输出语句3");}

输出结果是:

    输出语句2输出语句3

代码在进行除零操作时发生了异常,此时“输出语句1”将无法得到被调用的机会。一旦抛出异常,程序控制就会从try代码块中转移出来,进入catch代码块中。执行了catch语句后,就会继续运行整个try/catch代码块的下一行

五、多条catch子句

在有些情况下,一个代码块可能会引发多个异常。对于这种情况,需要指定两条或多条catch子句,用于捕获不同类型的异常。当抛出异常时,按顺序检查每条catch语句,执行类型和异常相匹配的第一条catch子句,忽略其他catch子句,并继续执行try/catch代码块后面的代码

需要注意的是,异常子类必须位于异常超类之前,因为使用了某个超类的catch语句会捕获这个超类及其所有子类的异常。因此,如果子类位于超类之后的话,永远也不会到达子类。不可到达的代码会被编译器提示错误

参照如下代码,通过Math的静态方法random来随机产生0和1两个随机数,生成的不同数值就会引发不同的异常,分别由不同的catch子句进行处理

    public static void main(String[] args) {    int random=(int) Math.round(Math.random());try{int a=10/random;int[] array={10};array[random]=1;}catch (ArithmeticException e) {System.out.println("ArithmeticException");}catch (ArrayIndexOutOfBoundsException e) {System.out.println("ArrayIndexOutOfBoundsException");}System.out.println("代码块结束");}

此外,也可以通过多重捕获的方式来使用相同的catch子句捕获两个或更多个异常。在catch子句中使用或运算符(|)分隔每个异常,每个多重捕获参数都被隐式地声明为final类型

    public static void main(String[] args) {    int random=(int) Math.round(Math.random());try{int a=10/random;int[] array={10};array[random]=1;}catch(ArithmeticException | ArrayIndexOutOfBoundsException e){System.out.println("两个异常之一");}}

六、throw

在之前的例子中,捕获的异常都是由Java运行时系统抛出的异常,可以通过throw语句显式地抛出异常

throw的一般形式如下所示:

throw ThrowableInstance 

ThrowableInstance必须是Throwable或其子类类型的对象。throw语句之后的执行流程会立即停止,所有的后续语句都不会执行,然后按顺序依次检查所有的catch语句,检查是否和异常类型相匹配。如果没有找到匹配的catch语句,那么默认的异常处理程序会终止程序并输出堆栈踪迹

例如,运行以下代码,将得到输出结果:“NullPointerException”

public class Demo {public static void demo(){throw new NullPointerException("NullPointer");}public static void main(String[] args) {try{demo();}catch (NullPointerException e) {System.out.println("NullPointerException");}}}

但如果catch子句的异常与throw抛出的异常类型不匹配时,异常将由Java默认的异常处理程序来处理

例如,运行以下代码:

public class Demo {public static void demo(){throw new NullPointerException("NullPointer");}public static void main(String[] args) {try{demo();}catch (ArrayIndexOutOfBoundsException e) {System.out.println("ArrayIndexOutOfBoundsException");}}}

运行结果是:

Exception in thread "main" java.lang.NullPointerException: NullPointerat Demo.demo(Demo.java:4)at Demo.main(Demo.java:9)

七、throws

如果方法可能引发自身不进行处理的异常,就必须通过throws关键字来向方法的调用者指明要抛出的异常类型。 方法可能抛出的所有异常都必须在throws子句中进行声明,否则将产生编译时错误

例如,参照以下代码,该程序试图抛出无法匹配的异常,因为程序没有指定throws子句来声明这一事实,所以程序无法编译

public class Demo {public static void demo(){throw new IllegalAccessException("IllegalAccess");}public static void main(String[] args) {demo();}}

为了使代码能够运行,需要将之进行如下修改

public class Demo {public static void demo() throws IllegalAccessException{throw new IllegalAccessException("IllegalAccess");}public static void main(String[] args) {try {demo();} catch (IllegalAccessException e) {System.out.println(e.getMessage());}}}

八、finally

当抛出异常后,方法的执行流程将不会按照原先的顺序进行,这对于某些方法来说是个问题。例如,如果在方法中打开了一个文件,我们并不希望因为抛出了异常导致关闭文件的代码被跳过而不执行。finally关键字就是来解决这种情况的。 使用finally可以创建一个代码块,该代码块会在执行try/catch代码块之后执行,且在执行try/catch代码块后面的代码之前执行。不管是否有异常抛出,都将执行finally代码块

只要方法从try/catch代码块内部返回到调用者,不管是通过未捕获的异常还是使用显式的返回语句,都会在方法返回之前执行finally子句

例如,如下的输出结果将是:2

public class Demo {public static int demo(){try{int a=10/0;System.out.println(a);}catch(Exception e){return 1;}finally {return 2;}}public static void main(String[] args) {System.out.println(demo());}}

九、链式异常

链式异常用于为异常关联另一个异常,第二个异常用于描述当前异常产生的原因。例如,某个方法从文件读取数值来作为除法运算的除数,由于发生了I/O错误导致获取到的数值是0,从而导致了ArithmeticException异常

如果想要让代码调用者知道背后的原因是I/O错误,使用链式异常就可以来处理这种情况以及其他存在多层异常的情况

为了使用链式异常,Throwable有两个构造函数和两个方法用于处理这种情况

两个构造函数:

    Throwable(Throwable cause)Throwable(String message, Throwable cause)

cause即是用于指定引发当前异常的背后原因,message则可以用于同时指定异常描述

两个方法:

    Throwable getCause()Throwable initCause(Throwable cause)

getCause() 方法用来返回引发当前异常的异常,如果不存在背后异常则返回null

initCause(Throwable cause) 方法将cause和明面上的异常关联到一起,并返回对异常的引用。因此可以在创建异常之后将异常和背后异常关联到一起。但是,背后异常只能设置一次,即initCause(Throwable cause) 方法只能调用一次。此外,如果通过构造函数设置了背后异常,也不能再使用该方法来设置背后异常了

例如,参照如下代码:

public class Demo {public static void demo(){NullPointerException nullPointerException=new NullPointerException("nullPointer");nullPointerException.initCause(new ArithmeticException("Arithmetic"));throw nullPointerException;}public static void main(String[] args) {try {demo();} catch (Exception e) {System.out.println(e.getMessage());System.out.println(e.getCause().getMessage());}}}

运行结果是:

nullPointer
Arithmetic 

链式异常可以包含所需要的任意深度,但是,过长的异常链可能是一种不良的设计

# 链接 Java程序员福利"常用资料分享"

java怎么碰到异常跳过继续执行_Java异常处理很难吗?BAT大厂的架构师是怎么处理Java异常的?...相关推荐

  1. 【Java从0到架构师】Zookeeper 应用 - Java 客户端操作、服务器动态感知、分布式锁业务处理

    分布式基石 Zookeeper 框架全面剖析 Java 客户端操作 Java 客户端 API 服务器的动态感知 服务注册 服务发现 分布式锁业务处理 单机环境(一个虚拟机中) 分布式环境_同名节点 分 ...

  2. java架构师之路:JAVA程序员必看的15本书的电子版下载地址

    java架构师之路:JAVA程序员必看的15本书的电子版下载地址 作为Java程序员来说,最痛苦的事情莫过于可以选择的范围太广,可以读的书太多,往往容易无所适从.我想就我自己读过的技术书籍中挑选出来一 ...

  3. java架构师主要负责什么_Java架构师主要学什么 Java架构师工资多少

    Java架构师主要学什么 Java架构师工资多少 Java架构师是当下一个热门的职业,这已成不争的事实.学习Java架构技术成目前较为流行的一种趋势,作为Java架构师主要学什么呢?Java架构师工资 ...

  4. java 异常的分类并举例_Java异常处理中的一些特殊情况举例

    只使用try和finally不使用catch的原因和场景JDK并发工具包中,很多异常处理都使用了如下的结构,如AbstractExecutorService,即只有try和finally没有catch ...

  5. JAVA报错是一层一层的吗_Java异常处理:给程序罩一层保险

    本着负责任的态度,我们程序员在写代码的时候,都非常的严谨.但程序在运行的时候,往往会出现一些令人意想不到的错误,导致那些不被期望的事件发生,最终,程序没有按照我们的预期正常地执行下去--异常发生了,是 ...

  6. 二十年架构师整理出的Java学习路线,学完年薪百万

    永不过时的编程语言--Java 编程开发. Java编程语言占比: 据官方数据统计,在全球编程语言工程师的数量上,Java编程语言以900万的程序员数量位居首位. 而且很多软件的开发都离不开Java编 ...

  7. 大厂资深架构师都在读的10本Java实战书籍,Java开发进阶必备书单

    入门 <SSM企业级框架实战> 作者: 肖睿/丁慧洁/张宁彬 **简介:**框架(Framework)的本质为某种应用的半成品,即把不同应用程序中的共性内容抽取出来而形成的半成品程序.SS ...

  8. java 资深_Java架构师之路:从Java码农到资深架构师

    写在开篇 不管是开发.测试.运维,每个技术人员心里都有一个成为技术大牛的梦,毕竟"梦想总是要有的,万一实现了呢"!正是对技术梦的追求,促使我们不断地努力和提升自己. 然而" ...

  9. 一线大厂架构师都推荐的Java零基础大全,附面试答案

    前言 Redis作为基于键值对的NoSQL数据库,具有高性能.丰富的数据结构.持久化.高可用.分布式等特性,同时Redis本身非常稳定,已经得到业界的广泛认可和使用.因此,作为一个Java开发者,掌握 ...

最新文章

  1. 【Python培训基础知识】Python生成器函数
  2. 活动的批输入监控ENV
  3. sqlserver和mysql运营_SQLServer和MySql的区别总结
  4. Ubuntu 20.04 LTS 发布最终 Beta 版本
  5. 华为2台3928千兆电口对接trunk启不来
  6. 输出字符串全排列 c语言,41.输出全排列-题解(C语言代码)
  7. 初中计算机七年级人教版目录,最新人教版初中数学目录(详细)
  8. 网上一好人收集的PDF制作软件大全
  9. YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5的发展(1)
  10. python怎么打e,python e怎么表示
  11. D. Relatively Prime Graph(构造+数论)
  12. Android登陆demo:界面设计及业务代码———Android菜鸟的成长日记
  13. fastjson 序列化问题:Comparison method violates its general contract
  14. HDLBits-Exams/ece241 2013 q4、Lemmings1、Lemmings2、Lemmings3、Lemmings4
  15. 产品运营数据分析—SPSS数据分组案例
  16. 分支-12. 计算火车运行时间
  17. C# 原子操作 Interlocked
  18. 运筹学与博弈论的关系
  19. 一种二值图像封闭孔洞的高效填充算法
  20. X509数字证书学习

热门文章

  1. InnoDB的内存结构和特性
  2. Redis事务深入解析和使用
  3. IDEA中Spring Boot项目报错:There was an unexpected error (type=Not Found, status=404)
  4. bool python 运算_python中的布尔操作
  5. linux 改变文件夹属性,技术|在Linux中用chattr和lsattr命令管理文件和目录属性
  6. ubuntu20.04自带python版本_替换 ubuntu 自带的python版本
  7. java系统项目分为哪五大层次?控制层_业务_一个项目中说系统分为表现层、控制层、逻辑层、DAO层和最终数据库五层架构-转...
  8. edge浏览器怎么恢复默认设置 edge恢复默认设置方法
  9. 深度技术win11 32位全新专业版系统v2021.07
  10. 自定义的全局公共样式