JAVA异常的捕获与处理

视频链接:https://edu.aliyun.com/lesson_1011_8939#_8939

java语言提供最为强大的支持就在于异常的处理操作上。

1,认识异常对程序的影响

异常指的是导致程序中断的一种指令流。下面先看没有异常产生的程序执行结果

范例:没有异常产生

 public class Main {
public static void main(String[] args) {
System.out.println("******* 程序开始执行 *******");
System.out.println("******* "+10/2);
System.out.println("******* 程序执行结束 *******");
}
}
 ******* 程序开始执行 *******
******* 5
******* 程序执行结束 *******

在程序执行正常的过程里面会发现,所有的程序会按照既定的结构从头到尾开始执行。

范例:产生异常

 public class Main {
public static void main(String[] args) {
System.out.println("******* 程序开始执行 *******");
System.out.println("******* "+10/0);
System.out.println("******* 程序执行结束 *******");
}
}
 ******* 程序开始执行 *******

 Exception in thread "main" java.lang.ArithmeticException: / by zero

 at Main.main(Main.java:4)

在出现错误之后,整个程序将不会按照既定的方式进行执行,而是中断了执行。那么为了保证程序出现了非致命错误后程序依然可以正常完成,所以就需要有一个完善的异常处理机制,以保证程序的顺利执行。

2,处理异常

在java中如果要进行异常处理,可以使用:try、catch、finally关键字。

结构:

 try {

     //可能出现异常的语句

 }[catch (异常类型 异常对象)]

     //异常处理

 }catch (异常类型 异常对象)]

     //异常处理

 }catch(异常类型 异常对象)]

     //异常处理

 }...][finally {

     //不管异常是否处理执行,本句都要执行;

 }]

范例:异常处理在此格式之中可以使用的组合为:①try...catch;②try...catch...finally;③try...finally。

 public class Main {
public static void main(String[] args) {
System.out.println("******* 程序开始执行 *******");
try{
System.out.println("******* "+10/0);
}catch (ArithmeticException e){
System.out.println("异常处理:"+e);
} System.out.println("******* 程序执行结束 *******");
}
}
 ******* 程序开始执行 *******
异常处理:java.lang.ArithmeticException: / by zero
******* 程序执行结束 *******

范例:使用printStackTrace()输出完整的异常信息现在可以发现即便出现了异常,我们的程序也可以正常执行完毕,所以此时的设计属于一个合理设计。但是有一个问题出现了:此时在进行异常处理的时候直接输出的是一个异常类的对象,那么对于此对象如果直接打印(调用toString()所得到的异常信息并不完整,那么如果想要获得非常完整的异常信息,则可以使用异常类中提供的printStackTrace()方法

 public class Main {
public static void main(String[] args) {
System.out.println("******* 程序开始执行 *******");
try{
System.out.println("******* "+10/0);
}catch (ArithmeticException e){
e.printStackTrace();
}
System.out.println("******* 程序执行结束 *******");
}
}
 ******* 程序开始执行 *******
java.lang.ArithmeticException: / by zero
at Main.main(Main.java:5)
******* 程序执行结束 *******

范例:使用finally语句对于异常处理格式也可以在最后追加一个finally程序块,表示异常处理后的出口,不管是否出现异常都处理。

 public class Main {
public static void main(String[] args) {
System.out.println("******* 程序开始执行 *******");
try{
//System.out.println("******* "+10/0); System.out.println("******* "+10/1);
}catch (ArithmeticException e){
e.printStackTrace();
}finally {
System.out.println("【不管是否出现异常都处理 finally】");
}
System.out.println("******* 程序执行结束 *******");
}
}
 ******* 程序开始执行 *******
java.lang.ArithmeticException: / by zero
at Main.main(Main.java:5)
【不管是否出现异常都处理 finally】
******* 程序执行结束 *******
 ******* 程序开始执行 *******
******* 10
【不管是否出现异常都处理 finally】
******* 程序执行结束 *******

3,处理多个异常

很多时候在程序执行的过程之中可能会产生若干个异常,那么这种情况下也可以使用多个catch进行异常捕获。现在假设通过初始化的参数来进行来个计算数值的设置。

范例:多个异常catch捕获

 public class Main {
public static void main(String[] args) {
System.out.println("******* 程序开始执行 *******");
try{
int x=Integer.parseInt(args[0]);
int y=Integer.parseInt(args[1]);
System.out.println("******* "+(x/y));
}catch (ArrayIndexOutOfBoundsException e){
e.printStackTrace();
}catch (NumberFormatException e){
e.printStackTrace();
}catch (ArithmeticException e){
e.printStackTrace();
}
finally {
System.out.println("【不管是否出现异常都处理 finally】");
}
System.out.println("******* 程序执行结束 *******");
}
}

①【未处理】程序执行的时候没有输入初始化参数(java JavaDemo);java.lang.ArrayIndexOutOfBoundsException那么对于此时的程序就有可能产生三类异常:

②【未处理】输入的数据不是数字(java JavaDemo a b);

java.lang.NumberFormatException

③【已处理】输入的被除数为零(java JavaDemo 10 0);

java.lang.ArithmeticException

现在即便有了异常处理语句,但是如果没有进行正确的异常捕获,那么程序也会导致中断(finally的代码依然执行),所以在这样的情况下就必须进行多个异常的捕获

范例:多个异常捕获

 public class Main {
public static void main(String[] args) {
System.out.println("******* 程序开始执行 *******");
try{
int x=Integer.parseInt(args[0]);
int y=Integer.parseInt(args[1]);
System.out.println("******* "+(x/y));
}catch (ArrayIndexOutOfBoundsException e){
e.printStackTrace();
}catch (NumberFormatException e){
e.printStackTrace();
}catch (ArithmeticException e){
e.printStackTrace();
}finally {
System.out.println("【不管是否出现异常都处理 finally】");
}
System.out.println("******* 程序执行结束 *******");
}
}

此时我们开发已经知道有那些异常了,那么又何必要用那个异常呢???直接多写点判断不就可以了。

4,异常处理流程

在进行异常处理的时候如果将所有可能已经明确知道要产生的异常捕获,虽然你可以得到非常良好的代码结构,但是这种代码编写是非常麻烦的,所以现在要想进行合理异常就必须清楚在异常产生之后程序到底做了哪些处理。

①在程序运行的过程中才会产生异常,而一旦程序执行中产生了异常之后,将自动进行指定的异常类对象实例化处理;

②如果此时程序之中并没有提供有异常处理的支持,则会采用JVM默认异常处理方式,首先进行异常信息的打印,而后直接退出当前的程序;

③此时程序中如果有存在异常处理,那么这个产生的异常类的实例化对象将会被try语句捕获;

④try捕获到异常之后与其匹配的catch中的异常类型进行依次的比对,如果此时与catch中的捕获异常类型相同,则认为应该使用此catch进行异常处理,如果不匹配则继续匹配后续的catch类型,如果没有任何的catch匹配成功,那么就表示该异常无法进行处理;

⑤不管是否处理语句都要处理finally语句,但是当执行完成finally的程序之后会进一步判断当前的异常是否已经处理过了,如果处理过了,则继续向后执行其他代码,如果没有没有处理则交由JVM进行默认处理。

通过分析可以发现在整个的异常处理之中实际上操作的还是一个异常类的实例化对象的类型就成为了理解异常处理的核心关键所在,在之前接触过了两种异常:

ArithmeticException()

ArrayIndexOutOfBoundsException

java.lang.Object

java.lang.Throwable

java.lang.Exception

java.lang.RuntimeException

java.lang.ArithmeticException

java.lang.Object

java.lang.Throwable

java.lang.Exception

java.lang.RuntimeException

java.lang.IndexOutOfBoundsException

java.lang.ArrayIndexOutOfBoundsException

可以发现在程序之中可以处理的异常最大的类型就是Throwable,而打开Throwable可以观察在此类中提供有两个子类

①Error:此时程序还未执行出现的错误,开发者无法处理;

②Exception:程序中出现的异常,开发者可以处理,真正在开发中需要关注的是Exception;

通过分析可以发现异常产生的时候会产生异常的实例化对象那么按照对象的应用原则,可以向父类转型,那么按照这样的逻辑,实际上所有的异常都可以使用Exception来处理。

范例:简化异常处理

 public class Main {
public static void main(String[] args) {
System.out.println("******* 程序开始执行 *******");
try{
int x=Integer.parseInt(args[0]);
int y=Integer.parseInt(args[1]);
System.out.println("******* "+(x/y));
}catch (Exception e){//最大范围的异常捕获
e.printStackTrace();}
finally {
System.out.println("【不管是否出现异常都处理 finally】");
}
System.out.println("******* 程序执行结束 *******");
}
}

在以后进行多个异常同时处理的时候要把捕获范围大的异常放在捕获范围小的异常之后。当你不确定可能产生那些异常的时候,这种处理方式是最方便的。但是如果这样处理也会产生一个问题,这种异常的处理形式虽然方便,但是它描述的错误信息不明确,所以分开处理异常是一种可以更加明确的处理方式。

5,throws关键字

通过之前的程序可以发现,在执行程序的过程中可能会产生异常,但是如果说现在假设你定义了一个方法,实际上就应该明确地告诉使用者,这个方法可能会产生何种异常,那么此时就可以在方法的声明上使用throws关键字。

范例:观察throws的使用

 class MyMath{
public static int div(int x,int y) throws Exception{
return x/y;
}
}
public class Main001 {
public static void main(String args[]){
try {
System.out.println(MyMath.div(10,0));
} catch (Exception e) {
e.printStackTrace();
}finally {
System.out.println("hello Mufasa");
}
}
}

范例:在主方法上继续抛出异常主方法本身也是一个方法,那么实际上主方法也可以继续向上抛出。

 class MyMath{
public static int div(int x,int y) throws Exception{
return x/y;
}
}
public class Main001 {
public static void main(String args[]) throws Exception{
System.out.println(MyMath.div(10,0));
}
}

如果主方法继续向上抛出异常,那么就表示此异常将交由JVM负责处理。

6,throw关键字(少s)

throw关键字,此关键字的主要作用在于表示手工进行异常的抛出,即:此时将手工产生一个异常类的实例化对象,并且进行异常的抛出处理。

范例:观察throw的使用

 public class Main002 {
public static void main(String[] args) {
try {//异常对象不是由系统生成的,而是由手工定义的
throw new Exception("自己抛出一个异常");
}catch (Exception e){
e.printStackTrace();
}
}
}

①throw:在代码块中使用的,主要是手工进行异常对象的抛出;面试题:请解释throws和throw的区别?

②throws:在方法定义上使用的,表示此方法中可能产生的异常明确告诉调用处,由调用处进行处理;

7,异常处理的标准格式

现在已经学习了大部分的异常处理格式:try、catch、finally、throw、throws,那么这些关键字在实际开发之中往往会一起进行使用,下面通过一个具体的程序进行分析。

现在要求定义一个可以实现除法计算的方法,在这个方法之中开发要求如下:

①在进行数学计算开始与结束的时候进行信息提示;

②如果在进行计算的过程之中产生了异常,则要交给调用处来处理。

class MyMath{
//异常要交给被调用处处理则一定要在方法上使用throw
public static int div(int x,int y) throws Exception{
int temp=0;
System.out.println("**** 【START】除法计算开始");
temp=x/y;
System.out.println("**** 【END】除法计算结束");//有异常不出来
return temp;
}
}
public class Main001 {
public static void main(String args[]) {
try {
System.out.println(MyMath.div(10,0));
} catch (Exception e) {
e.printStackTrace();
}finally {
System.out.println("hello Mufasa");
}
}
}
 **** 【START】除法计算开始
java.lang.ArithmeticException: / by zero
at MyMath.div(Main001.java:6)
at Main001.main(Main001.java:18)
hello Mufasa
 class MyMath{
//异常要交给被调用处处理则一定要在方法上使用throw
public static int div(int x,int y) throws Exception{
int temp=0;
System.out.println("**** 【START】除法计算开始");
try {
temp=x/y;
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println("**** 【END】除法计算结束");
}
return temp;
}
}
public class Main001 {
public static void main(String args[]) {
try {
System.out.println(MyMath.div(10,0));
} catch (Exception e) {
e.printStackTrace();
}finally {
System.out.println("hello Mufasa");
}
}
}
 **** 【START】除法计算开始

 java.lang.ArithmeticException: / by zero

 at MyMath.div(Main001.java:7)

 at Main001.main(Main001.java:23)

 **** 【END】除法计算结束

 0

 hello Mufasa
 class MyMath{
//异常要交给被调用处处理则一定要在方法上使用throw
public static int div(int x,int y) throws Exception{
int temp=0;
System.out.println("**** 【START】除法计算开始");
try {
temp=x/y;
}catch (Exception e){
throw e;//向上层抛异常对象
}finally {
System.out.println("**** 【END】除法计算结束");
}
return temp;
}
}
public class Main001 {
public static void main(String args[]) {
try {
System.out.println(MyMath.div(10,0));
} catch (Exception e) {
e.printStackTrace();
}finally {
System.out.println("hello Mufasa");
}
}
}
 **** 【START】除法计算开始
**** 【END】除法计算结束
java.lang.ArithmeticException: / by zero
at MyMath.div(Main001.java:7)
at Main001.main(Main001.java:23)
hello Mufasa

对于此类操作实际上可以简化,省略掉catch与throw的操作。

try...finally的操作:

 class MyMath{
//异常要交给被调用处处理则一定要在方法上使用throw
public static int div(int x,int y) throws Exception{
int temp=0;
System.out.println("**** 【START】除法计算开始");
try {
temp=x/y;
}finally {
System.out.println("**** 【END】除法计算结束");
}
return temp;
}
} public class Main001 {
public static void main(String args[]) {
try {
System.out.println(MyMath.div(10,0));
} catch (Exception e) {
e.printStackTrace();
}finally {
System.out.println("hello Mufasa");
}
}
}

在以后实际开发过程中,这种异常的处理格式是最为重要的,尤其是当与一些资源进行访问操作的时候尤其重要。

8,RuntimeException

通过之前的分析可以发现只要方法后面带有throws往往都是告诉用户本方法可能产生的异常是什么,所以这个时候可以观察一段代码。

 public class Main003 {
public static void main(String[] args) {
int num=Integer.parseInt("123");
}
}
 public static int parseInt(String s) throws NumberFormatException

这个方法明确的抛出了异常,但是在处理的时候并没有强制性要求处理,观察一下NumberFormatException的继承结构,同时也观察数学异常类的继承结构打开Integer类中的parseInt()方法的定义

ArithmeticException()

NumberFormatException()

java.lang.Object

java.lang.Throwable

java.lang.Exception

java.lang.RuntimeException

java.lang.ArithmeticException

java.lang.Object

java.lang.Throwable

java.lang.Exception

java.lang.RuntimeException

java.lang.IllegalArgumentException

java.lang.NumberFormatException

如果现在所有程序执行上只要使用了throws定义的方法都必须要求开发者进行手工处理,那么这个代码的编写就太麻烦了,所以在设计的过程之中,考虑到代码的编写的方便,所以提供有一个灵活的、可选的异常处理父类“RuntimeException”,这个类的子类可以不需要强制性的处理。

面试题:请解释RuntimeException与Exception的区别?请列举出几个常见的RuntimeException;

①RuntimeException是Exception的子类;

②RuntimeException标注的异常可以不需要进行强制性处理,而Exception需要进行强制性处理;

①常见的RuntimeException:

IndexOutOfBoundsException(范围越界异常)、

NumberFormatException(数据格式异常)、

NullPointerException(空指针异常)

9,自定义异常类

在JDK之中提供有大量的异常类型,但是在实际的开发之中可能这些异常类型未必够你使用,你不可能所有的设计里面都只是抛出Exception,所以这个时候就需要考虑进行自定义异常类。但是对于自定义异常也有两种实现方案:继承Exception或者继承RuntimException

范例:实现自定义异常

RuntimeException

 class BombException extends RuntimeException{
public BombException(String msg){
super(msg);
}
}
class Food{
public static void eat(int num) throws BombException{
if (num>10){
throw new BombException("吃太多,肚子爆");
}else {
System.out.println("正常吃,不怕胖");
}
}
}
public class Main004 {
public static void main(String[] args) {
Food.eat(11);
}
}

Exception

 class BombException extends Exception{
public BombException(String msg){
super(msg);
}
}
class Food{
public static void eat(int num) throws BombException{
if (num>10){
throw new BombException("吃太多,肚子爆");
}else {
System.out.println("正常吃,不怕胖");
}
}
}
public class Main004 {
public static void main(String[] args) {
try {
Food.eat(11);
}catch (BombException e){
e.printStackTrace();
} }
}

在以后的项目开发过程中会接触大量的自定义异常处理,如果遇见了你不清楚的异常,最简单的方式就是通过搜索引擎查询一下异常可能产生的原因。

10,assert

从JDK1.4后追加了一个断言的功能,确定代码执行到某行后一定是所期待的结果。在实际开发之中,对于断言而言,并不一定是准确的,也有可能出现偏差,但是这种偏差不应该影响程序的正常执行。

范例:断言的使用

 public class Main005 {
public static void main(String[] args) {
int x=10;
//中间会出现许多的x变量的操作步骤
assert x==100:"x的数值不是100";
}
}

(java -ea Main005

Exception in thread "main" java.lang.AssertionError: x的数值不是100 at Main005.main(Main005.java:5)

如果现在要想执行断言,则必须在程序执行的时候加入参数(java -ea Main005)

所以在java里面并没有将断言设置成为一个程序必须执行的步骤,需要特定的环境下可以开启。

Java异常模块的更多相关文章

  1. Java开源生鲜电商平台-异常模块的设计与架构(源码可下载)

    Java开源生鲜电商平台-异常模块的设计与架构(源码可下载) 说明:任何一个软件系统都会出现各式各样的异常与错误,我们需要根据异常的情况进行捕获与分析,改善自己的代码,让其更加的稳定的,快速的运行,那 ...

  2. Java异常之自定义异常

    哎呀,妈呀,又出异常了!俗话说:"代码虐我千百遍,我待代码如初恋". 小Alan最近一直在忙着工作,已经很久没有写写东西来加深自己的理解了,今天来跟大家聊聊Java异常.Java异 ...

  3. 2.Java异常学习

    1.Java异常的概念 异常的例子 1.除法就是一个需要捕获异常的例子,除数又可能是0 异常处理的基本流程如下 一旦发生异常,就使得程序不按照原来的流程继续的运行下去 a.程序抛出异常 try{ th ...

  4. Java 异常讲解(转)

    六种异常处理的陋习 你觉得自己是一个Java专家吗?是否肯定自己已经全面掌握了Java的异常处理机制?在下面这段代码中,你能够迅速找出异常处理的六个问题吗?   1 OutputStreamWrite ...

  5. 一篇不错的讲解Java异常的文章(转载)

    http://www.blogjava.net/freeman1984/archive/2007/09/27/148850.html 六种异常处理的陋习 你觉得自己是一个Java专家吗?是否肯定自己已 ...

  6. Java基础10:全面解读Java异常

    更多内容请关注微信公众号[Java技术江湖] 这是一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux ...

  7. 写给大忙人的ELK最新版6.2.4学习笔记-Logstash和Filebeat解析(java异常堆栈下多行日志配置支持)

    接前一篇CentOS 7下最新版(6.2.4)ELK+Filebeat+Log4j日志集成环境搭建完整指南,继续对ELK. logstash官方最新文档https://www.elastic.co/g ...

  8. Java - 异常解析基础

    java提高篇(十六)-----异常(一) 一.为什么要使用异常 首先我们可以明确一点就是异常的处理机制可以确保我们程序的健壮性,提高系统可用率.虽然我们不是特别喜欢看到它,但是我们不能不承认它的地位 ...

  9. 理解Java异常

    一.Java异常的简介 Java异常是Java提供的一种识别及响应错误的一致性机制.具体来说,异常机制提供了程序退出的安全通道.当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器.Ja ...

随机推荐

  1. 20191121-5 Scrum立会报告+燃尽图 02

    此作业要求参见https://edu.cnblogs.com/campus/nenu/2019fall/homework/10066 一.小组情况 组长:贺敬文组员:彭思雨 王志文 位军营 徐丽君队名 ...

  2. Notepad++格式化xml(转)

    转自:http://www.herongyang.com/XML/NPP-XML-Tools-Plugin-Download-and-Install.html Downloading and inst ...

  3. Python 文件writelines() 方法和处理双层列表

    概述 writelines() 方法用于向文件中写入一序列的字符串. 这一序列字符串可以是由迭代对象产生的,如一个字符串列表. 换行需要制定换行符 \n. 语法 writelines() 方法语法如下 ...

  4. Ubuntu下使用AMD APP编写OpenCL程序

    对于Ubuntu或其近亲(Lubuntu.Kubuntu.Mint等)编写OpenCL程序也不会太难.由于本例用的是AMD APP SDK,因此需要AMD的GPU以及相关驱动.首先,去AMD官网下载G ...

  5. syspolicy_purge_history作业故障排除

    描述 我们有一台数据库服务器windows 2012 r2 上有安装sql server 2012 和sql server 2016双实例,后续又把sql 2016的服务全部停用,即只保留sql 20 ...

  6. Python中类的继承代码实例

    Python中类的继承代码实例 这篇文章主要介绍了Python中类的继承代码实例,本文直接给出代码及运行效果,需要的朋友可以参考下 相对于C 的继承编写,Python更简洁,而且效率也是很高的,下面编 ...

  7. panic 捕获及 throw 崩溃

    一,go 语言 panic 报错捕获  使用 go 语言的同学在真实项目中应该经常出现空指针使用等 panic 报错,这类报错与 C++ 中的 try-catch 模块不同,go 语言会一直将当前 p ...

  8. Android 单元测试学习计划

    网上查了一下Android单元测试相关的知识点,总结了一个学习步骤: 1. 什么是单元测试2. 单元测试正反面: 2.1. 重要性 2.2. 缺陷 2.3. 策略3. 单元测试的基础知识: 3.1. ...

  9. windows端口映射

    1. 查看netsh interface portproxy show all 2. 添加端口映射转发netsh interface portproxy add v4tov4 listenaddres ...

  10. vue-cli3 取消eslint 校验代码 真正的解决办法

    在网上找了各种办法都没解决,看了下文档就解决了 关闭vue-cli3.0 报错:eslint-disable-next-line to ignore the next line.   注意我这里是VU ...