目录

  • 定义概念:
  • 异常类型
  • 异常处理:
    • try...catch
    • try...catch finally
    • throws关键字
    • throw关键字
    • throw和throws什么区别?
  • 自定义异常

定义概念:

所谓异常就是程序运行时可能出现的一些错误,比如试图打开一个根本不存在的文件、配置问题、错误输入等问题,异常处理将会改变程序的控制流程,让程序有机会对错误做出处理。语法错误和逻辑错误不是异常。

java异常处理过程
(1)当程序运行到某一句时,发生了异常,那么程序会先停下来
(2)程序会在这句代码处,查看原因,生成一个合理“异常对象”,然后“抛”出
(3)JVM会检测在这句代码的外围,是否有try…catch结构,可以“捕获”异常对象。

如果可以捕获,那么程序再处理完异常后,继续下面的运行,不会崩溃;
如果不能捕获,那么会把这个异常继续抛给“上级”,如果“上级”能处理,那么程序从“上级"处理完的代码后面继续运行;

如果上级也不能处理,那么继续往上抛,一直到达JVM,那么就“崩溃”

演示代码:

public static void main(String[] args) {int sum = 0;System.out.println("sum = " + sum);testInput();  //第18行代码System.out.println("main的其他代码");}public static void testInput(){Scanner input = new Scanner(System.in);try {System.out.print("请输入一个整数:");int num = input.nextInt(); //第24行代码} catch (ArrayIndexOutOfBoundsException e) {//获取数组越界异常对象System.out.println("输入有误");//这里 只是提醒,没有让他 重新输入}System.out.println("其他的代码");}

分析:
从第34行开始,由于输入不匹配,抛出输入不匹配异常对象,尽管有try…catch可以捕获异常对象,但是catch的是数组越界异常对象,因此无法捕获,于是将异常对象继续抛给上级。因为是在main函数调用的方法,于是就抛给了main函数(第18行),但是main函数也无法处理,于是继续抛给虚拟机,最终程序崩溃。

修改过后:

public static void main(String[] args) {int sum = 0;System.out.println("sum = " + sum);try {testInput();} catch (InputMismatchException e) {System.out.println("成功捕获异常对象");}System.out.println("main的其他代码");}public static void testInput(){Scanner input = new Scanner(System.in);try {System.out.print("请输入一个整数:");int num = input.nextInt();} catch (ArrayIndexOutOfBoundsException e) {//获取数组越界异常对象System.out.println("输入有误");//这里 只是提醒,没有让他 重新输入}System.out.println("其他的代码");}

异常类型

1、异常的公共父类:java.lang.Throwable
(1)只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句“抛”出。
(2)只有此类或其子类之一才可以是 catch 子句中的参数类型。

2、Throwable又分为两大派别:
(1)Error:错误
一般指严重错误,一般合理的应用程序不应该试图去捕获它。
如果出现这个问题,要么需要升级修改程序,要么需要升级架构,要么需要升级硬件。
例如:报了一个OutOfMemoryError
经典代表:VirtualMachineError(堆内存溢出OutOfMemoryError,栈内存溢出StackOverflowError)

(2)Exception:异常
一般异常,合理的应用程序应该试图去捕获它。

3、Exception还可以分为两大类:
(1)运行时异常(RuntimeException或它子类):又称为非受检异常。
编译时,编译器是不会提醒你做处理的,只有运行期间,才会发生。

运行时异常是不建议用try…catch,因为它发生频率太高,而且一般都是很不应该发生的问题。
例如:空指针异常,数组下标越界异常,类型转换异常等,这些异常完全可以避免掉。
但是如果实在没有考虑到,也可以通过try…catch处理。

(2)编译时异常,除了RuntimeException系列以外的,都是编译时异常。又称为受检异常。
编译时,编译器会强制要求程序员编写处理的代码,如果你不编写,那么就编译不通过。
例如:FileNotFoundException,IOException等

异常处理:

try…catch

1、格式:

 try{可能发生异常的代码}catch(异常类型1  异常对象名){//异常对象名绝大多数都是写e处理这个异常的代码}catch(异常类型2  异常对象名){//异常对象名绝大多数都是写e处理这个异常的代码
}catch(异常类型3  异常对象名){//异常对象名绝大多数都是写e处理这个异常的代码}... ...

2、异常对象的常用方法
(1)e.printStackTrace();
打印异常的详细信息,包括对象跟踪信息,即这个异常对象一路经过了哪些方法
(2)e.getMessage();
返回异常对象中简单的错误信息提示

3、打印异常/错误信息
System.err.println(xx);打印错误信息(打印红色字体)
System.out.println(xx);打印正常信息

4、多个catch分支,如何匹配和执行的?
从上到下依次判断,一旦有一个满足,后面就不看了。
建议:如果多个catch中的异常类型有大小包含关系,那么小的在上,大的在下,如果没有大小包含关系,顺序随意。

5、如果catch,可以捕获try中发生的异常,那么程序,会从try…catch下面的代码继续运行 ,不会崩溃。
如果catch无法捕获try中发生的异常,那么就会导致当前方法结束,并把异常对象抛出调用者。
如果调用者可以处理,那么从调用者处理代码的后面继续运行,否则继续往上抛,最终到达JVM,程序就崩溃了。

演示代码:

//从命令行接收2个整数,求商public static void main(String[] args) {try {int a = Integer.parseInt(args[0]);//第一个参数赋值给a变量int b = Integer.parseInt(args[1]);//第二个参数赋值给b变量int shang = a/b;System.out.println(a +"/" + b + "=" + shang);} catch (NumberFormatException e) {e.printStackTrace();//标准的//System.err.println(e.getMessage());//System.out.println(e.getMessage());} catch (ArrayIndexOutOfBoundsException e){e.printStackTrace();} catch (ArithmeticException e){e.printStackTrace();} catch (Exception e){e.printStackTrace();}               System.out.println("其他的代码....");}


try…catch finally

格式:

try{可能发生异常的代码
}catch(异常类型1  异常对象名){//异常对象名绝大多数都是写e处理这个异常的代码}catch(异常类型2  异常对象名){//异常对象名绝大多数都是写e处理这个异常的代码
}catch(异常类型3  异常对象名){//异常对象名绝大多数都是写e处理这个异常的代码
}... ...finally{不管try中是否发生异常,也不管catch是否可以捕获异常,这里代码都必须执行
}

一般用于编写释放资源,断开连接等代码

特殊情况:可以没有catch部分

 try{
}finally{}

演示代码:

public static void main(String[] args) {try {int a = 1;int b = 0;System.out.println(a/b);} catch (ArrayIndexOutOfBoundsException e) {e.printStackTrace();} finally{System.out.println("最终块");}}

补:finally与return混用:

public static void main(String[] args) {int num = getNum(4);System.out.println(num);//0}public static int getNum(int a){int result = 10;try{System.out.println(a/0);if(a > 0){result = 20;return result;}else if(a < 0){result = -20;return result;}else{return result;}}catch(Exception e){System.out.println("exception");result = 0;return result;}finally{result = 30;System.out.println("finally");//return result;//如果有这句,结果就变成30}}

finally与return混用:

(1)不管try中是否发生异常,也不管catch是否可以捕获异常,也无论try或catch中是否有return。 finally中的代码都必须执行
(2)如果finally中有return,就从finally块的的return回去。
(3)如果finally中没有return,那么先把try或catch中该执行的执行完(包括把返回值的结果放到要带回调用处的操作数栈的位置),在return结束当前方法之前,先走一下finally,然后回去结束当前方法.

结论,如果finally中没有return,finally中的代码不影响返回值。

但是如果try-catch语句执行了程序退出代码,即执行System.exit(0);,则不执行finally子语句(当然包括其后的所有语句)

throws关键字

异常处理的方式之一:
在当前方法中直接用try…catch处理
异常处理的方式之二:
在当前方法中不处理,扔/抛给调用者处理(throws的作用)

格式:

【修饰符】 返回值类型  方法名(【形参列表】)throws 异常列表们{}
说明:throws后面可以跟好几个异常,顺序无所谓,每一个异常之间使用,分割

throws的好处:
(1)throws:告知被调用者,我这个方法可能会抛出哪些异常,使得调用者可以明确的知道应该catch什么异常。
如果没有throws,那么调用者就不清楚,只能按照Exception处理,或者根据错误经验来处理。
2)编译时异常,如果在当前方法中不用try…catch处理,编译不通过,那么可以通过throws明确的说明,抛给调用者处理

演示代码:

public static void main(String[] args) {try {divide(1,1);} catch (ArithmeticException e) {e.printStackTrace();} catch (RuntimeException e) {e.printStackTrace();}try {copy("1.txt","2.txt");} catch (FileNotFoundException e) {e.printStackTrace();}         }public static void divide(int a, int b)throws ArithmeticException,RuntimeException{System.out.println(a/b);}public static void copy(String srcFile, String destFile) throws FileNotFoundException{FileInputStream fis = new FileInputStream(srcFile);//用来读取srcFile文件的内容}

关于方法重写时,对throws抛出的异常的要求:
子类重写的方法抛出的异常类型必须<=父类被重写的方法抛出的异常类型。
例如:
Exception > RuntimeException > ArrayIndexOutOfBoundsException

public static void main(String[] args) {Father f = new Son();//多态引用try {f.method();} catch (RuntimeException e) {e.printStackTrace();}Father f2 = new Son();Object str = f2.test();}class Father{public void method()throws RuntimeException{//....}public Object test(){return null;}
}
class Son extends Father{@Overridepublic void method()throws ArrayIndexOutOfBoundsException{//....}@Overridepublic String test(){return "";}
}

throw关键字

异常的对象的创建和抛出有两种方式:
(1)JVM创建并抛出
(2)程序员new出来,然后由throw抛出。throw用于手动抛出异常对象。可以代替return语句,结束当前的方法。

 public static void main(String[] args) {Account a = new Account(100);try {boolean flag = a.withdraw(500);//如果没有异常,取款成功System.out.println("取款成功" + flag);} catch (IllegalArgumentException e) {e.printStackTrace();} catch (RuntimeException e) {e.printStackTrace();}}
}class Account {private double balance;public Account(double balance) {super();this.balance = balance;}public boolean withdraw(double money) {if (money < 0) {throw new IllegalArgumentException("取款金额" + money + "有问题,取款金额不能小于0");}if (money > balance) {throw new RuntimeException("余额不足");}balance -= money;return true;}
}

throw和throws什么区别?

(1)throw用于方法内部,手动抛出异常对象,是个可执行的语句。throws用于方法声明。
(2)throw后面抛出异常对象且只有一个,throws声明异常类型且可以是多种。

自定义异常

如果系统预定义的异常类型,
例如:ArrayIndexOutOfBoundsException
ClassCastException//类型转换异常
NullPointerException
ArithmeticException
InputMisMatchException
IllegalAugumentException

发现不能准确的表达你当前的异常类型的意思时,可以选择自定义一个异常类。

1、自定义的要求:
(1)必须继承Throwable或它的子类
但是实际开发中,一般继承RuntimeException和Exception

(2)建议保留两种构造器的形式
①无参构造
②带给父类的message属性赋值的构造器

2、如何使用自定义异常
只能使用throw语句进行手动抛出。它不能由JVM自动抛出。

3、建议
在自定义异常时,异常的类型名非常重要,见名知意。

演示代码:

 public static void main(String[] args) {Account a = new Account(100);try {a.withdraw(-100);} catch (MoneyCannotNegativeException e) {System.out.println(e.getMessage());e.printStackTrace();}}
}//例如:声明一个异常类型,表示金额不能为负数
class MoneyCannotNegativeException extends Exception {public MoneyCannotNegativeException() {super();}public MoneyCannotNegativeException(String message) {super(message);}}class Account {private double balance;public Account(double balance) {super();this.balance = balance;}public boolean withdraw(double money) throws MoneyCannotNegativeException {if (money < 0) {throw new MoneyCannotNegativeException("取款金额" + money + "有问题,取款金额不能小于0");}if (money > balance) {throw new RuntimeException("余额不足");}balance -= money;return true;}
}

Java——异常处理(详解)相关推荐

  1. Java异常处理详解

    1. Java Exception 介绍 1.1 什么是java异常 1.java异常是程序运行时遇到不被期望的事件,影响了程序的正常的运行. 2.异常的分类: 语法编译错误: 程序运行的时候错误: ...

  2. Java异常详解及如何处理

    来源:Java异常详解及如何处理 简介 程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常.异常发生时,是任程序自生自灭,立刻退出终止,还是输出错误给用户?或者用C语言 ...

  3. Apache Thrift - java开发详解

    2019独角兽企业重金招聘Python工程师标准>>> Apache Thrift - java开发详解 博客分类: java 架构 中间件 1.添加依赖 jar <depen ...

  4. Java泛型详解-史上讲解最详细的,没有之一

    目录 1. 概述 2. 一个栗子 3. 特性 4. 泛型的使用 4.1 泛型类 4.2 泛型接口 4.3 泛型通配符 4.4 泛型方法 4.4.1 泛型方法的基本用法 4.4.2 类中的泛型方法 4. ...

  5. Java虚拟机详解----JVM常见问题总结

    [正文] 声明:本文只是做一个总结,有关jvm的详细知识可以参考本人之前的系列文章,尤其是那篇:Java虚拟机详解04----GC算法和种类.那篇文章和本文是面试时的重点. 面试必问关键词:JVM垃圾 ...

  6. java 泛型详解、Java中的泛型方法、 java泛型详解

    本文参考java 泛型详解.Java中的泛型方法. java泛型详解 概述 泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用. 什么是泛型?为什么要使用泛型? 泛型,即& ...

  7. 最详细的java泛型详解

    来源:最详细的java泛型详解 对java的泛型特性的了解仅限于表面的浅浅一层,直到在学习设计模式时发现有不了解的用法,才想起详细的记录一下. 本文参考java 泛型详解.Java中的泛型方法. ja ...

  8. Java基础——Java NIO详解(一)

    一.基本概念 1.I/0简介 I/O即输入输出,是计算机与外界世界的一个借口.IO操作的实际主题是操作系统.在java编程中,一般使用流的方式来处理IO,所有的IO都被视作是单个字节的移动,通过str ...

  9. Java基础——Java NIO详解(二)

    一.简介 在我的上一篇文章Java NIO详解(一)中介绍了关于标准输入输出NIO相关知识, 本篇将重点介绍基于网络编程NIO(异步IO). 二.异步IO 异步 I/O 是一种没有阻塞地读写数据的方法 ...

  10. Java基础——Java IO详解

    一.概述 1.Java IO Java IO即Java 输入输出系统.不管我们编写何种应用,都难免和各种输入输出相关的媒介打交道,其实和媒介进行IO的过程是十分复杂的,这要考虑的因素特别多,比如我们要 ...

最新文章

  1. python中内建函数_python常用内建函数
  2. 十年——透过BILL的眼睛
  3. 【原】高清显示屏原理及设计方案
  4. OpenGL多维数据集的透视图渲染
  5. Single Area OSPF
  6. spring项目概念-IOCDI
  7. 一口气搞懂「链表」,就靠这20+张图了
  8. 论坛高级签名_首届中国定制白酒高峰论坛在天津盘山举行
  9. 华为云ModelArts图深度学习,学习知识还能考取微认证
  10. HAOI2008 移动玩具
  11. 六款Linux常用远程连接工具介绍,看看哪一款最适合你
  12. UEFI shell - 标准应用程序的编译和加载过程
  13. MySQL安装步骤(ZIP版)
  14. 人工智能挑战教师角色独特性 与教育教学融合显现独特优势
  15. 5G网络规划面临的挑战
  16. 万网域名绑定阿里云服务器
  17. 麻省理工学院公开课:信号与系统:模拟与数字信号处理 调幅演示
  18. Ubuntu18.04安装坚果云
  19. jQuery事件绑定和解绑
  20. 仙侣情缘之麒麟劫java_《仙侣情缘之麒麟劫》最终支线攻略

热门文章

  1. 介绍几本COM的书籍
  2. sql语句 多条件排序
  3. C++类与对象再升华
  4. 基于Qt5模拟企业微信聊天界面(QWidget)
  5. php rfc3986规范,C# 符合RFC3986标准的urlencode 类
  6. 小偷能获取的最大金额 环形小区 [分类讨论第一家是否能偷]
  7. 如何解决窗口任务栏有360浏览器闪烁网页广告图标?
  8. oracle协议适配器错误tns,ORA-12560: TNS: 协议适配器错误
  9. nginx同一端口多域名转发
  10. 关于最近面试的通过2个offer然后被刷