Java基础篇:异常处理
文章目录
- 异常概述与异常体系结构
- 常见异常
- 异常处理机制
- 异常处理机制一:try-catch-finally
- 异常处理机制二:throws
- 手动抛出异常:thow
- 如何自定义一个异常类?
- 总结
异常概述与异常体系结构
异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。(开发过程中的语法错误和逻辑错误不是异常)
Java程序在执行过程中所发生的异常事件可分为两类:
- Error:Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:StackOverflowError和OOM。一般不编写针对性的代码进行处理
- Exception: 其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:
- 空指针访问
- 试图读取不存在的文件
- 网络连接中断
- 数组角标越界
对于这些错误,一般有两种解决方法:一是遇到错误就终止程序的运行。另一种方法是由程序员在编写程序时,就考虑到错误的检测、错误消息的提示,以及错误的处理。
捕获错误最理想的是在编译期间,但有的错误只有在运行时才会发生。
比如:除数为0,数组下标越界等分类:
编译时异常
和运行时异常
1.运行时异常
- 是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该积极避免其出现的异常。
java.lang.RuntimeException
类及它的子类都是运行时异常。 - 对于这类异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。
- 是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该积极避免其出现的异常。
2.编译时异常
- 是指编译器要求必须处置的异常。即程序在运行时由于外界因素造成的一般性异常。编译器要求Java程序必须捕获或声明所有编译时异常。
- 对于这类异常,如果程序不处理,可能会带来意想不到的结果。
异常的体系结构
上图中,红色的表示:受检(checked)异常(编译时异常);蓝色的表示:非受检(unchecked)异常(运行时异常)
- java.lang.Throwable
|-----java.lang.Error:一般不编写针对性的代码进行处理。
|-----java.lang.Exception:可以进行异常的处理
|------编译时异常(checked)
|-----IOException
|-----FileNotFoundException
|-----ClassNotFoundException
|------运行时异常(unchecked,RuntimeException)
|-----NullPointerException
|-----ArrayIndexOutOfBoundsException
|-----ClassCastException
|-----NumberFormatException
|-----InputMismatchException
|-----ArithmeticException
从程序执行过程,看编译时异常和运行时异常
编译时异常:执行javac.exe命名时,可能出现的异常
运行时异常:执行java.exe命名时,出现的异常
常见异常
- java.lang.RuntimeException
- ClassCastException
- ArrayIndexOutOfBoundsException
- NullPointerException
- ArithmeticException
- NumberFormatException
- InputMismatchException
- java.io.IOExeption
- FileNotFoundException
- EOFException
- java.lang.ClassNotFoundException
- java.lang.InterruptedException
- java.io.FileNotFoundException
- java.sql.SQLException
public class ExceptionDemo {//******************以下是编译时异常***************************@Testpublic void test7(){File file = new File("hello.txt");FileInputStream fis = new FileInputStream(file);int data = fis.read();while(data != -1){System.out.print((char)data);data = fis.read();}fis.close();}//******************以下是运行时异常***************************//ArithmeticException@Testpublic void test6(){int a = 10;int b = 0;System.out.println(a / b);}//InputMismatchException@Testpublic void test5(){Scanner scanner = new Scanner(System.in);int score = scanner.nextInt();System.out.println(score);scanner.close();}//NumberFormatException@Testpublic void test4(){String str = "123";str = "abc";int num = Integer.parseInt(str);}//ClassCastException@Testpublic void test3(){Object obj = new Date();String str = (String)obj;}//IndexOutOfBoundsException@Testpublic void test2(){String str = "abc";System.out.println(str.charAt(3));}//NullPointerException@Testpublic void test1(){String str = null;System.out.println(str.charAt(0));}
}
异常处理机制
Java异常处理的抓抛模型
过程一:“抛”:程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象,并将此对象抛出。一旦抛出对象以后,其后的代码就不再执行
关于异常对象的产生:
- ① 系统自动生成的异常对象
- ② 手动的生成一个异常对象,并抛出(throw)
过程二:“抓”:可以理解为异常的处理方式:
- ① try-catch-finally
- ② throws
异常处理机制一:try-catch-finally
在编写程序时,经常要在可能出现错误的地方加上检测的代码,如进行x/y运算时,要检测分母为0,数据为空,输入的不是数据而是字符等。过多的if-else分支会导致程序的代码加长、臃肿,可读性差。因此采用异常处理机制。
Java采用的异常处理机制,是将异常处理的程序代码集中在一起,与正常的程序代码分开,使得程序简洁、优雅,并易于维护。
Java异常处理的方式
- 方式一:try-catch-finally
- 方式二:throws+异常类型
Java提供的是异常处理的抓抛模型。
Java程序的执行过程中如出现异常,会生成一个异常类对象,该异常对象将被提交给Java运行时系统,这个过程称为抛出(throw)异常。
异常对象的生成
- 由虚拟机自动生成:程序运行过程中,虚拟机检测到程序发生了问题,如果在当前代码中没有找到相应的处理程序,就会在后台自动创建一个对应异常类的实例对象并抛出——自动抛出
- 由开发人员手动创建:
Exception exception = new ClassCastException();
——创建好的异常对象不抛出对程序没有任何影响,和创建一个普通对象一样
异常的抛出机制
如果一个方法内抛出异常,该异常对象会被抛给调用者方法中处理。如果异常没有在调用者方法中处理,它继续被抛给这个调用方法的上层方法。这个过程将一直继续下去,直到异常被处理。这一过程称为捕获(catch)异常。
如果一个异常回到main()方法,并且main()也不处理,则程序运行终止。
程序员通常只能处理Exception,而对Error无能为力。
异常处理是通过try-catch-finally语句实现的。
try {...... //可能产生异常的代码
} catch (ExceptionName1 e) {...... //当产生ExceptionName1型异常时的处置措施
} catch (ExceptionName2 e) {...... //当产生ExceptionName2型异常时的处置措施
} finally {...... //无论是否发生异常,都无条件执行的语句
}
说明:
- finally是可的。
- 使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配
- 一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。一旦处理完成,就跳出当前的try-catch结构(在没写finally的情况。继续执行其后的代码
- catch中的异常类型如果没子父类关系,则谁声明在上,谁声明在下无所谓;catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则,报错
- 常用的异常对象处理的方式: ① String getMessage() ② printStackTrace()
- 在try结构中声明的变量,再出了try结构以后,就不能再被调用
- try-catch-finally结构可以嵌套
try
捕获异常的第一步是用try{…}语句块选定捕获异常的范围,将可能出现异常的代码放在try语句块中。
catch (Exceptiontype e)
在catch语句块中是对异常对象进行处理的代码。每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。
如果明确知道产生的是何种异常,可以用该异常类作为catch的参数;也可以用其父类作为catch的参数。
比如 : 可以用ArithmeticException类作为参数的地方 , 就可以用RuntimeException类作为参数,或者用所有异常的父类Exception类作为参数。但不能是与ArithmeticException类无关的异常,如NullPointerException(catch中的语句将不会执行)。
捕获异常的有关信息:
与其它对象一样,可以访问一个异常对象的成员变量或调用它的方法
- getMessage() 获取异常信息,返回字符串
- printStackTrace() 获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
finally
- 捕获异常的最后一步是通过finally语句为异常处理提供一个统一的出口,使得在控制流转到程序的其它部分以前,能够对程序的状态作统一的管理。
- 不论在try代码块中是否发生了异常事件,catch语句是否执行,catch语句是否有异常,catch语句中是否有return,finally块中的语句都会被执行。
- finally语句和catch语句是任选的
- 像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中
异常处理机制一:举例
@Test
public void test(){String[] friends = {"AA","BB","CC"};try {for (int i = 0; i < 5; i++) {System.out.println(friends[i]);}}catch (ArrayIndexOutOfBoundsException e){System.out.println("index err");}System.out.println("this is the end");
}
输出结果为:
AA
BB
CC
index err
this is the end
public class ExceptionDemo {int x;public static void main(String[] args) {int y;ExceptionDemo c = new ExceptionDemo();try {y = 3 / c.x;} catch (ArithmeticException e) {System.out.println("divide by zero error!");}System.out.println("program ends ok!");}
}
输出结果:
divide by zero error!
program ends ok!
异常处理机制二:throws
声明抛出异常是Java中处理异常的第二种方式
如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地
声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者
负责处理。
在方法声明中用throws
语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
throws + 异常类型
写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。
一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后异常类型时,就会被抛出。异常代码后续的代码,就不再执行!
声明抛出异常举例:
public void readFile(String file) throws FileNotFoundException {……
// 读文件的操作可能产生FileNotFoundException类型的异常
FileInputStream fis = new FileInputStream(file);
..……
}
声明抛出异常示例
public class ThrowsTest {public static void main(String[] args) {ThrowsTest t = new ThrowsTest();try {t.readFile();} catch (IOException e) {e.printStackTrace();}}public void readFile() throws IOException {FileInputStream in = new FileInputStream("atguigushk.txt");int b;b = in.read();while (b != -1) {System.out.print((char) b);b = in.read();}in.close();}
}
重写方法声明抛出异常的原则
重写方法不能抛出比被重写方法范围更大的异常类型。在多态的情况下,对methodA()方法的调用-异常的捕获按父类声明的异常处理。
public class A {public void methodA() throws IOException {……
} }
public class B1 extends A {public void methodA() throws FileNotFoundException {……
} }
public class B2 extends A {public void methodA() throws Exception { //报错
……
} }
方法重写的规则之一:
子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
两种异常处理机制方式的对比
- try-catch-finally:真正的将异常给处理掉了。
- throws的方式只是将异常抛给了方法的调用者。并没真正将异常处理掉。
在开发中应该如何选择两种处理方式?
- 如果父类中被重写的方法没throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果子类重写的方法中异常,必须使用try-catch-finally方式处理。
- 执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。建议这几个方法使用throws的方式进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理。
手动抛出异常:thow
在程序执行中,除了自动抛出异常对象的情况之外,我们还可以手动的throw一个异常类的对象。
Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出,也可根据需要使用人工创建并抛出。
- 首先要生成异常类对象,然后通过throw语句实现抛出操作(提交给Java运行环境)。
IOException e = new IOException();
throw e;
- 可以抛出的异常必须是
Throwable
或其子类的实例。下面的语句在编译时将会产生语法错误:
throw new String("want to throw");
应用案例
class Student{ private int id;public void regist(int id) throws Exception {if(id > 0){this.id = id;}else{//手动抛出异常对象throw new MyException("不能输入负数");} }@Overridepublic String toString() {return "Student [id=" + id + "]";}
}
##自定义异常类
- 一般地,用户自定义异常类都是
RuntimeException
的子类 - 自定义异常类通常需要编写几个重载的构造器
- 自定义异常需要提供
serialVersionUID
- 自定义的异常通过
throw
抛出 - 自定义异常最重要的是异常类的名字,当异常出现时,可以根据名字判断异常类型。
如何自定义一个异常类?
- 继承于现有的异常结构:
RuntimeException
、Exception
- 提供全局常量:
serialVersionUID
- 提供重载的构造器
/*** 自定义异常类MyException,用于描述数据取值范围错误信息,自定义的异常类* 必须继承现有的异常类*/
public class MyException extends RuntimeException{static final long serialVersionUID = -7034897193246939L;private int idNumber;public MyException(){}public MyException(String message, int idNumber){super(message);this.idNumber = idNumber;}public int getIdNumber() {return idNumber;}public void setIdNumber(int idNumber) {this.idNumber = idNumber;}
}
public class MyExpTest {public void regist(int num) throws MyException {if (num < 0)throw new MyException("人数为负值,不合理", 3);elseSystem.out.println("登记人数" + num);}public void manager() {try {regist(-100);} catch (MyException e) {System.out.println("登记失败,出错种类" + e.getIdNumber()+"\t"+e.getMessage());}System.out.println("本次登记操作结束");}public static void main(String args[]) {MyExpTest t = new MyExpTest();t.manager();}
}
判断程序的输出结果
public class ReturnExceptionDemo {static void methodA() {try {System.out.println("进入方法A");throw new RuntimeException("制造异常");}finally {System.out.println("用A方法的finally");}}static void methodB() {try {System.out.println("进入方法B");return;} finally {System.out.println("调用B方法的finally");}}public static void main(String[] args) {try {methodA();} catch (Exception e) {System.out.println(e.getMessage());}methodB();}
}
输出结果为:
进入方法A
用A方法的finally
制造异常
进入方法B
调用B方法的finally
总结
Java基础篇:异常处理相关推荐
- 菜鸟学习笔记:Java基础篇7(包装类、时间相关类、文件类、异常处理类)
菜鸟学习笔记:Java其他常用类 基本数据类型包装类 时间处理和文件处理相关类 Date时间类 SimpleDateFormat Calendar日历类 文件类 异常机制 异常的概念 Java异常处理 ...
- Java基础篇1——变量与数据类型
Java基础篇1--变量与数据类型 1.标识符命名规则 标识符以由大小写字母.数字.下划线(_)和美元符号($)组成,但是不能以数字开头. 大小写敏感 不能与Java语言的关键字重名 不能和Java类 ...
- 菜鸟学习笔记:Java基础篇6(数组、字符串)
菜鸟学习笔记:Java常用类(数组.字符串) 数组 概述 数组的定义 二维数组 数组查找和排序 查找 排序 数组运用--字符串 不可变字符序列(String) 可变字符序列(StringBuilder ...
- Android面试题Java基础篇
Android面试题Java基础篇,由本人整理汇总,后续将继续推出系列篇,如果喜欢请持续关注和推荐,更多精彩内容可以关注微信公众号(Android高级编程):android-tech 系列文章目录: ...
- 《Java 后端面试经》Java 基础篇
<Java 后端面试经>专栏文章索引: <Java 后端面试经>Java 基础篇 <Java 后端面试经>Java EE 篇 <Java 后端面试经>数 ...
- 你所需要的java基础篇深入解析大汇总
java基础篇深入解析大总结 java基础(一) 深入解析基本类型 java基础(二) 自增自减与贪心规则 java基础(三) 加强型for循环与Iterator java基础(四) java运算顺序 ...
- Java基础篇4——数组
Java基础篇4--数组 1.数组的概念 当需要在Java程序中记录单个数据内容时,则声明一个变量即可 当需要在Java程序中记录多个类型相同的数据内容时,则声明一个一维数 组即可,一维数组本质上就是 ...
- Java基础篇3——流程控制
Java基础篇3--流程控制 1.顺序结构 正常代码的流程即是顺序流程 2.分支结构 2.1.if-else分支 if(条件表达式) {语句块1; } if(条件表达式) {语句块1; } else ...
- Java基础篇2——运算符
Java基础篇2--运算符 1.运算符 1.1.算数运算符 +表示加法运算符 -表示减法运算符 *表示乘法运算符 /表示除法运算符 %表示取余运算符 1.2.关系运算符 所有以关系运算符作为最终运算的 ...
- 菜鸟学习笔记:Java基础篇5(抽象类与接口、回调函数、内部类)
菜鸟学习笔记:Java面向对象篇下 抽象类 接口 回调函数 内部类 成员内部类 匿名内部类 抽象类 通过前面知识的学习,抽象类这个概念应该不难理解,但比较容易和后面要说的接口混淆,而且在面试中也比较爱 ...
最新文章
- rust 关于ARM 板卡的使用
- TrackViewState到底是干什么的
- 通过WebAssembly在移动端解码H.265
- 20应用统计考研复试要点(part31)--简答题
- k8s中使用MySQL共享存储_Kubernetes创建挂载共享存储的容器
- Java StringBuffer相关解惑
- 数据结构探险——图篇
- 操作系统(李治军) L8 CPU管理的直观想法
- 深入理解Unity刚体(Rigidbody)、碰撞器(Collider)、触发器(Trigger)
- vue mqtt测试工具使用(一)
- matlab绘制布尔运算图,最强干货——PPT布尔运算最全攻略
- ionic中android的返回键
- 100条经典C++笔试题目及答案分享
- n维椭球体积公式_初中化学知识点:物质的量及其计算公式
- python mysql日期输出格式_Python/Shell/MySQL时间获取与格式转换
- 命令行检查win10自动唤醒原因
- AttributeError: ‘HistGradientBoostingClassifier‘ object has no attribute ‘_n_features‘
- 年薪10万与年薪100万的程序员,写出代码的区别
- winscp如何查看隐藏文件
- 优雅代码的秘密,只因为我掌握了Java Stream 流操作
热门文章
- 唱好铁血丹心谐音正规_济南公司起名:四个字寓意好的公司名字怎么样选择?...
- oracle有一百个人围一圈报数,案例:Oracle创建表时报session超过最大值 ORA-00018 证明递归ses...
- Docker虚拟化解析
- java 同步包_Java并发程序设计(四)JDK并发包之同步控制
- CF558E A Simple Task 线段树
- jdk8新特性_JDK8与JDK9新特性学习
- 抢红包算法 c语言,红包分配算法,抢红包算法
- 文件转换html文件失败,pandoc文档转换失败,出现错误67
- 图论分析方法gretna_基于磁共振的多模态分析对血管性认知障碍患者脑网络的研究...
- 【图论技巧】点边转化(拆点和拆边)