当前位置: 首页 > news >正文

#Java异常处理

传统的语言如何处理

在一些传统的语言(如C语言中)

  • if语句来判断是否出现了例外

  • 全程变量ErrNo

但这有几个缺点

  • 正常处理与异常处理的代码同样处理

  • 可读性(readability)差

  • 每次调用一个方法时都进行错误检查

  • 可维护性( maintainability )差错误由谁处理不请

  • 职责不清

Java中的异常处理特点:

Java中处理异常包括

  1. 抛出(throw)异常

  2. 运行时系统在调用栈中查找

    • 从生成异常的方法开始进行回溯,直到找到:

  3. 捕获(catch) 异常的代码
    调用过程如下所示:

图片描述

代码

例子一

没有使用Java异常处理机制

public class Test {
    public static void main(String [] args){
        for(int i = 0; i < 2;i++){
            System.out.print(i + " ");
            System.out.println(1/0);//throw an exception.
        }
    }
}

运行结果:

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

1/0明显非法,所以产生了异常ArithmeticException对象,这个对象是Exception的子类。

例子二

以下开始用异常处理机制捕获该异常:

public class Test {
    public static void main(String [] args){
        for(int i = 0; i < 2;i++){
            System.out.print(i + " ");
            try{
                System.out.println(1/0);//An exception will throw from here.
            }
            catch(Exception ex){//在这里,这个Exception 其实就是ArithmeticException
            //这里用到了程序运行时的多态思想。
            //实际中应指定具体的作为ex的类型,更加有针对性。
                System.out.println("exception handling...");//
            }
        }
    }
}

运行结果:

0 exception handling...
1 exception handling...

这样确实能捕获到相应的异常对象。尽管什么也没做(只是打印字符串),却让编译器不再报告之前的异常。因为上述catch(type ex){...}就是负责处理异常。

例子三

当捕获到异常后,程序的运行过程会怎样?

public class Test2 {
    public static void main(String[] args){
        try{
            for (int i = 0; i< 2; i++){
                System.out.print(i + " ");
                System.out.println(1/0);//exception being thrown from here.Then it wil jump directly to the corresponding catch block.
                System.out.println("This line is supposed to be ignored");
            }
        }
        //handling the exception.
        catch(Exception ex){
            System.out.println("Exception handling...");
        }
        System.out.println("End of the main()");
    }
}

运行结果:

0 exception handling...
End of the main()

for不可能循环到i = 2;因为在i = 1时已经抛出了异常。只要产生了异常,转入对应的catch(type ex){...}catch(type ex)必须在参数里面说明捕获的对象是哪类型的。
throw语句就像一个调用函数,当程序运行中抛出了一个异常对象,就会调用对应的catch(type ex){}来处理。但它又不像调用函数。因为在调用完后,它不会返回到throw语句,而是接着catch之后的语句。所以System.out.println("This line is supposed to be ignored");这条语句被没有执行;for循环也相当于被中断了。

Java的异常处理语句

抛出异常

throw 异常对象;

捕获异常

try{
    语句组
}
catch(异常类名 异常形式参数名){
    异常处理语句组; 
}
catch(异常类名 异常形式参数名){
    异常处理语句组; 
}
finally{
    异常处理语句组;
}

其中,catch语句可以0至多个,可以没有finally语句

异常的分类

Throwable

  • Error: JVM的错误(一般来说,我们很难处理这里异常)

  • Exception: 异常(重点关注)
    注:一般所说的异常,是指Exception及其子类

图片描述

Exception类

构造方法

public Exception();
public Exception(String message);
Exception(String message, Throwable cause) ;

方法

getMessage()
getCause()
printStackTrace()

代码

例子一

仍然是没有使用Java的异常处理机制:

import java.util.Scanner;
public class QuotientWithMethod {
    public static int quotient(int num1, int num2){
        if(num2 == 0){
            log("Divisor cannot be zero");
            System.exit(1);
        }
        return num1/num2;
    }
    public static void log(String s){
        System.out.println(s);
    }
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        //prompt user to enter two integers
        int num1 = input.nextInt();
        int num2 = input.nextInt();
        int result = quotient(num1,num2);//调用函数
        System.out.println(num1 + "/" + num2 + "is" + result );
    }
}

运行结果

input two numbers:
1 0
Divisor cannot be zero

在没用使用异常处理机制的情况下,出现了异常情况的话,在被调用的函数中,处理异常情况——这里是直接退出了程序;

例子二

用异常处理机制的好处是职责分明:被调函数中抛出异常,主调函数中负责处理异常。

import java.util.Scanner;
public class QuotientWithException {
    public static int  quotient(int num1, int num2){
        if(num2 == 0){
            throw new ArithmeticException("Divisor cannot be zero");//用关键字throw抛出异常对象,这里是调用构造器来新建对象
        }//但不做处理
        return num1/num2;
    }
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        System.out.println("input two numbers:");
        int num1 = input.nextInt();
        int num2 = input.nextInt();
        boolean goOn = true;
        do {
            try {
                int result = quotient(num1, num2);
                System.out.println("num1" +"/" + "num2" + "is" +result);
                goOn = false;
            }
            //职责分明;一个负责抛出异常,一个负责处理异常.
            catch(ArithmeticException ex){
                //在主调函数中处理异常
                System.out.println("Exception occur:" + "Divisor cannot be zero. \n input again,please:");
                num1 = input.nextInt();
                num2 = input.nextInt();
                //int result = quotient(num1, num2);
                //System.out.println("num1" +"/" + "num2" + "is" +result);
            }
        }while(goOn);
        //处理后,进入catch{}后的语句.
        System.out.println("End of main().");
    }
}

运行结果

input two numbers:
1 0
Exception occur:Divisor cannot be zero. 
 input again,please:
1 1
num1/num2is1
End of main().

在被调函数中,只负责抛出异常:throw new ArithmeticException("Divisor cannot be zero");,主调函数中catch(ArithmeticException ex){...}指定将要捕获的对象的类型,并做相应的处理,这里要求重新输入。

多异常的处理

  • 子类异常要排在父类异常的前面,也就是先处理具体的异常,后处理抽象的异常。

  • finally语句,无论是否有异常都要执行,即使其中有break,return等语句

  • 在编译时,finally部分代码生成了多遍

Exception分两种

RuntimeException及其子类,可以不明确处理;否则,称为受检的异常(checked Exception)

RuntimeException, Error, and their subclasses are known as unchecked exceptions. All other exceptions are known as checked exceptions, meaning that the compiler forces the programmer to check and deal with them in a try-catch block or declare it in the method header.--Introduction to Java

对于受检的异常(checked Exception),要求明确进行语法处理:

  • 要么捕(catch)

  • 要么抛(throws):在方法的签名后面用throws xxxx来声明

    • 在子类中,如果要覆盖父类的一个方法,若父类中的方法声明了 throws异常,则子类的方法也可以throws异常

    • 可以抛出子类异常(更具体的异常),但不能抛出更一般的异常

自定义异常类

创建用户自定义异常时

  • 继承自Exception类或某个子Exception类

  • 定义属性和方法,或重载父类的方法

    • 这样getMessage(), toString(), printStackTrace()都会从Exception继承下来。

重抛异常及异常链接( Chained Exceptions)

对于异常,不仅要进行捕获处理,有时候还需要将此异常进一步传递给调用者,以 便让调用者也能感受到这种异常。这时可以在catch语句块或finally语句块中采取,以下三种方式:

  • 将当前捕获的异常再次抛出:
    throw e;

  • 重新生成一个异常,并抛出,如:
    throw new Exception("some message");

  • 重新生成并抛出一个新异常,该异常中包含了当前异常的信息,如:throw new Exception("some message",e);e.getCause() 来得到内部异常

相关文章:

  • 1.请求安全-- 一个简单的 单设备登录 单点登录
  • CST UTC
  • 在CentOS上安装与配置Tomcat
  • Modular Multiplicative Inverse(模乘逆元)
  • 线程同步辅助类——CountDownLatch
  • Java中的并发工具
  • ShareSDK的使用文章
  • Linux查看程序端口占用情况
  • 如何在VS2008中自定义多项目模板
  • 程序员,我们都是夜归人【转】
  • 【架构】微服务系列文章
  • 快速查询Python脚本语法
  • 基础业务集成开发平台(BusinessWorks) - 概要设计篇
  • java基础----java调用oracle存储过程(转)
  • linux GTK 安装
  • (ckeditor+ckfinder用法)Jquery,js获取ckeditor值
  • 【面试系列】之二:关于js原型
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • Bytom交易说明(账户管理模式)
  • cookie和session
  • Create React App 使用
  • eclipse的离线汉化
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • JAVA多线程机制解析-volatilesynchronized
  • Laravel 菜鸟晋级之路
  • Mac转Windows的拯救指南
  • mysql 数据库四种事务隔离级别
  • sessionStorage和localStorage
  • Sublime text 3 3103 注册码
  • vue从入门到进阶:计算属性computed与侦听器watch(三)
  • vue脚手架vue-cli
  • 包装类对象
  • 程序员该如何有效的找工作?
  • 多线程 start 和 run 方法到底有什么区别?
  • 技术:超级实用的电脑小技巧
  • 排序(1):冒泡排序
  • 前端面试之闭包
  • Prometheus VS InfluxDB
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • ​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​
  • #Z0458. 树的中心2
  • (3)nginx 配置(nginx.conf)
  • (delphi11最新学习资料) Object Pascal 学习笔记---第7章第3节(封装和窗体)
  • (八)光盘的挂载与解挂、挂载CentOS镜像、rpm安装软件详细学习笔记
  • (附源码)ssm户外用品商城 毕业设计 112346
  • (附源码)ssm教师工作量核算统计系统 毕业设计 162307
  • (六)Hibernate的二级缓存
  • (未解决)macOS matplotlib 中文是方框
  • (一)appium-desktop定位元素原理
  • (转)程序员技术练级攻略
  • .net core webapi Startup 注入ConfigurePrimaryHttpMessageHandler
  • .NET/C# 避免调试器不小心提前计算本应延迟计算的值
  • .NET/C# 使用 ConditionalWeakTable 附加字段(CLR 版本的附加属性,也可用用来当作弱引用字典 WeakDictionary)
  • @property @synthesize @dynamic 及相关属性作用探究
  • [⑧ADRV902x]: Digital Pre-Distortion (DPD)学习笔记