异常
异常体系
异常的根类是java.lang.Throwable,其下有两个子类:java.lang.Error与java.lang.Exception,平时所说的异常指java.lang.Exception
Throwable体系:
- Error:严重错误Error,无法通过处理的错误,只能事先避免,好比绝症。
- 例如:StackOverflowError和OOM(OutOfMemoryError)
- Exception表示异常,其他因编程错误或偶然的外在因素导致的一般性问题,程序员可以通过代码的方式纠正,使程序继续运行,是必须要处理的
- 例如:空指针访问、试图读取不存在的文件、网络连接中断、数组角标越界
Throwable中的常用方法:
- public void printStackTrace():打印异常的详细信息
- 包含了异常的类型,异常的原因,还包括异常出现的位置,在开发和调试阶段都得使用printStackTrace
- public String getMessage():获取发生异常的原因
- 提示给用户的时候,就提示错误原因
异常分类
- 编译时期异常:checked异常。在编译时期,就会检查如果没有处理异常,则编译失败
- 运行时期异常:runtime异常。在运行时期,检查异常,在编译时期,运行异常不会被编译器检测到(不报错)。(如数组索引越界异常,类型转换异常)。程序员应该积极避免其出现的异常,而不是使用try…catch处理,因为这类异常很普遍,若都使用try…catch或throws处理可能会对程序的可读性和运行效率产生影响
异常的处理
Java异常处理的五个关键字:try、catch、finally、throw、throws
异常throw
Java程序的执行过程中如出现异常,会生成一个异常类对象,该异常对象将被提交给Java运行时系统,这个过程称为抛出(throw)异常。异常对象的生成有两种方式:
- 由虚拟机自动生成:程序运行过程中,虚拟机检测到程序发生了问题,如果在当前代码中没有找到相应的处理程序,就会在后台自动创建一个对应异常类的实例对象并抛出——自动抛出
- 由开发人员手动创建:Exception exception = new ClassCastException();——创建好的异常对象不抛出对程序没有任何影响,和创建一个普通对象一样,但是一旦throw抛出,就会对程序运行产生影响了
手动抛出异常:
1、创建一个异常对象,封装一些提示信息
2、将这个异常对象告知给调用者,throw异常对象
throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行
使用格式:
1 throw new 异常类名(参数);
例如:
1 throw new NullPointerException("要访问的arr数组不存在"); 2 throw new ArrayIndexOutOfBoundsException("该索引在数组中不存在,已超出范围");
1 public class ThrowDemo { 2 public static void main(String[] args) { 3 //创建一个数组 4 int[] arr = {2,4,52,2}; 5 //根据索引找对应的元素 6 int index = 4; 7 int element = getElement(arr, index); 8 9 System.out.println(element); 10 System.out.println("over"); 11 } 12 /* 13 * 根据 索引找到数组中对应的元素 14 */ 15 public static int getElement(int[] arr,int index){ 16 if(arr == null){ 17 /* 18 判断条件如果满足,当执行完throw抛出异常对象后,方法已经无法继续运算。 19 这时就会结束当前方法的执行,并将异常告知给调用者。这时就需要通过异常来解决。 20 */ 21 throw new NullPointerException("要访问的arr数组不存在"); 22 } 23 //判断 索引是否越界 24 if(index<0 || index>arr.length-1){ 25 /* 26 判断条件如果满足,当执行完throw抛出异常对象后,方法已经无法继续运算。 27 这时就会结束当前方法的执行,并将异常告知给调用者。这时就需要通过异常来解决。 28 */ 29 throw new ArrayIndexOutOfBoundsException("哥们,角标越界了~~~"); 30 } 31 int element = arr[index]; 32 return element; 33 } 34 }
声明异常throws
声明异常:将问题标识出来,报告给调用者。如果方法内通过throw抛出了编译时异常,而没有捕获处理,那么必须通过throws进行声明,让调用者去处理
关键字throws运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常)
声明异常格式:
1 修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{ }
1 import java.io.File; 2 import java.io.FileNotFoundException; 3 4 public class TestException { 5 public static void main(String[] args) throws FileNotFoundException { 6 readFile("不敲代码学会Java秘籍.txt"); 7 } 8 9 // 如果定义功能时有问题发生需要报告给调用者。可以通过在方法上使用throws关键字进行声明 10 public static void readFile(String filePath) throws FileNotFoundException{ 11 File file = new File(filePath); 12 if(!file.exists()){ 13 throw new FileNotFoundException(filePath+"文件不存在"); 14 } 15 } 16 17 }
throws用于进行异常类的声明,若该方法可能有多种异常情况产生,那么在throws后面可以写多个异常类,用逗号隔开
1 import java.io.File; 2 import java.io.FileNotFoundException; 3 4 public class TestException { 5 public static void main(String[] args) throws FileNotFoundException,IllegalAccessException { 6 readFile("不敲代码学会Java秘籍.txt"); 7 } 8 9 // 如果定义功能时有问题发生需要报告给调用者。可以通过在方法上使用throws关键字进行声明 10 public static void readFile(String filePath) throws FileNotFoundException,IllegalAccessException{ 11 File file = new File(filePath); 12 if(!file.exists()){ 13 throw new FileNotFoundException(filePath+"文件不存在"); 14 } 15 if(!file.isFile()){ 16 throw new IllegalAccessException(filePath + "不是文件,无法直接读取"); 17 } 18 //... 19 } 20 21 }
捕获异常try…catch
如果异常出现的话,会立刻终止程序,所以我们得处理异常:
1、该方法不处理,而是声明抛出,由该方法的调用者来处理(throws)
2、在方法中使用try-catch的语句块来处理异常
try-catch的方式就是捕获异常
Java中对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式的处理
捕获异常语法如下:
1 try{ 2 编写可能会出现异常的代码 3 }catch(异常类型1 e){ 4 处理异常的代码 5 //记录日志/打印异常信息/继续抛出异常 6 }catch(异常类型2 e){ 7 处理异常的代码 8 //记录日志/打印异常信息/继续抛出异常 9 } 10 ....
try:该代码块中编写可能产生异常的代码
catch:用来进行某种异常的捕获,实现对捕获到的异常进行处理
- 可以有多个catch块,按顺序匹配
- 如果多个异常类型有包含关系,那么小上大下
1 public class TestException { 2 public static void main(String[] args) { 3 try { 4 readFile("不敲代码学会Java秘籍.txt"); 5 } catch (FileNotFoundException e) { 6 // e.printStackTrace(); 7 // System.out.println("好好敲代码,不要老是想获得什么秘籍"); 8 System.out.println(e.getMessage()); 9 } catch (IllegalAccessException e) { 10 e.printStackTrace(); 11 } 12 13 System.out.println("继续学习吧..."); 14 } 15 16 // 如果定义功能时有问题发生需要报告给调用者。可以通过在方法上使用throws关键字进行声明 17 public static void readFile(String filePath) throws FileNotFoundException, IllegalAccessException{ 18 File file = new File(filePath); 19 if(!file.exists()){ 20 throw new FileNotFoundException(filePath+"文件不存在"); 21 } 22 if(!file.isFile()){ 23 throw new IllegalAccessException(filePath + "不是文件,无法直接读取"); 24 } 25 //... 26 } 27 28 }
如何获取异常信息:
Throwable类定义了一些查看方法:
- public String getMessage():获取异常的描述信息,原因(提示给用户的时候,就提示错误原因)
- public void printStackTrace():打印异常的跟踪栈信息并输出到控制台
包含了异常的类型,异常的原因,还包括异常出现的位置,在开发和调试阶段,都得使用PrintStackTrace
finally块
finally:有一些特定的代码无论一场是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些语句执行不到。而finally就是解决这个问题的,在finally代码块中存放的代码都是一定会被执行的
当我们在try语句块中打开了一些物理资源(磁盘文件/网络连接/数据库连接等),我们都得在使用完之后,最终关闭打开的资源
finally的语法:
1 try{ 2 3 }catch(...){ 4 5 }finally{ 6 无论try中是否发生异常,也无论catch是否捕获异常,也不管try和catch中是否有return语句,都一定会执行 7 } 8 9 或 10 try{ 11 12 }finally{ 13 无论try中是否发生异常,也不管try中是否有return语句,都一定会执行 14 }
注意:finally不能单独使用
finally与return
形式一:从try回来
1 public class TestReturn { 2 public static void main(String[] args) { 3 int result = test("12"); 4 System.out.println(result); 5 } 6 7 public static int test(String str){ 8 try{ 9 Integer.parseInt(str); 10 return 1; 11 }catch(NumberFormatException e){ 12 return -1; 13 }finally{ 14 System.out.println("test结束"); 15 } 16 } 17 }
形式二:从catch回来
1 public class TestReturn { 2 public static void main(String[] args) { 3 int result = test("a"); 4 System.out.println(result); 5 } 6 7 public static int test(String str){ 8 try{ 9 Integer.parseInt(str); 10 return 1; 11 }catch(NumberFormatException e){ 12 return -1; 13 }finally{ 14 System.out.println("test结束"); 15 } 16 } 17 }
形式三:从finally回来
1 public class TestReturn { 2 public static void main(String[] args) { 3 int result = test("a"); 4 System.out.println(result); 5 } 6 7 public static int test(String str){ 8 try{ 9 Integer.parseInt(str); 10 return 1; 11 }catch(NumberFormatException e){ 12 return -1; 13 }finally{ 14 System.out.println("test结束"); 15 return 0; 16 } 17 } 18 }
异常注意事项
多个异常使用捕获该如何处理?
1、多个异常分别处理
2、多个异常一次捕获,多次处理(推荐)
3、多个异常一次捕获一次处理
一般使用一次捕获多次处理方式,格式如下:
1 try{ 2 编写可能会出现异常的代码 3 }catch(异常类型A e){ 当try中出现A类型异常,就用该catch来捕获. 4 处理异常的代码 5 //记录日志/打印异常信息/继续抛出异常 6 }catch(异常类型B e){ 当try中出现B类型异常,就用该catch来捕获. 7 处理异常的代码 8 //记录日志/打印异常信息/继续抛出异常 9 }
注意:这种异常处理方式,要求多个catch中的异常不能相同,并且若catch中的多个异常之间有子父类异常的关系,那么子类异常要求在上面的catch处理,父类异常在下面的catch处理
- 运行时异常被抛出可以不处理,即不捕获也不声明抛出
- 如果finally有return语句,永远返回finally中的结果,避免该情况
- 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常
- 父类方法没有抛出异常,子类重写父类该方法时也不能抛出异常。此时子类方法中产生了编译时异常,只能捕获处理,不能声明抛出
自定义异常
异常类如何定义:
1、自定义一个编译期异常:自定义类并继承于java.lang.Exception
2、自定义一个运行时期的异常类:自定义类并继承于java.lang.RuntimeException
模拟注册操作,如果用户名已存在,则抛出异常并提示:该用户名已经被注册
首先定义一个登录异常类RegisterException:
1 // 业务逻辑异常 2 public class RegisterException extends Exception { 3 /** 4 * 空参构造 5 */ 6 public RegisterException() { 7 } 8 9 /** 10 * 11 * @param message 表示异常提示 12 */ 13 public RegisterException(String message) { 14 super(message); 15 } 16 }
模拟登录操作,使用数组模拟数据库中存储的数据,并提供当前注册账号是否存在方法用于判断
1 public class Demo { 2 // 模拟数据库中已存在账号 3 private static String[] names = {"bill","hill","jill"}; 4 5 public static void main(String[] args) { 6 //调用方法 7 try{ 8 // 可能出现异常的代码 9 checkUsername("nill"); 10 System.out.println("注册成功");//如果没有异常就是注册成功 11 }catch(RegisterException e){ 12 //处理异常 13 e.printStackTrace(); 14 } 15 } 16 17 //判断当前注册账号是否存在 18 //因为是编译期异常,又想调用者去处理 所以声明该异常 19 public static boolean checkUsername(String uname) throws LoginException{ 20 for (int i=0; i<names.length; i++) { 21 if(names[i].equals(uname)){//如果名字在这里面 就抛出登陆异常 22 throw new RegisterException("亲"+name+"已经被注册了!"); 23 } 24 } 25 return true; 26 } 27 }
- 从Exception类或者它的子类派生一个子类即可
- 习惯上,自定义异常类应该包含两个构造器:一个是无参构造,另一个是带有详细信息的构造器
- 自定义的异常只能通过throw抛出
- 自定义异常最重要的是异常类的名字,当异常出现时,可以根据名字判断异常类型
原文地址:https://www.cnblogs.com/daidai66/p/11945040.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Kafka安装(极简版)
- parallelStream的坑,不踩不知道,一踩吓一跳
- leetcode链表之删除链表的节点
- Windows 技术篇-通过注册表查找vc运行库所在位置实战演示,通过ProductCode查看vc++运行库安装位置
- Python 库安装问题-whl is not a supported wheel on this platform.原因及解决办法
- 安装Go运行环境
- Python 语法问题-module 'pip' has no attribute 'pep425tags',告诉你如何正确查看pip支持,32位、64位查看pip支持万能方法
- 使用matplotlib绘制3D图表
- 微服务的用户认证与授权杂谈(下)
- Python 库安装问题-用pip安装pyHook3报错,原因及解决办法
- 微服务的用户认证与授权杂谈(上)
- Python 技术篇-win32、amd64结尾的whl库该选哪个,如何查看python平台支持
- Python 基础篇-pip卸载python库方法,pip命令大全
- Python 技术篇-pip安装的python库缓存位置查看方法,如何查看python库源码
- Redis持久化 - RDB和AOF