零基础学Java第二十一讲---异常(1)
目录
一、异常的概念与体系结构
1、异常的概念
2、之前写代码时经常遇到的异常
2.1算术异常
2.2数组越界异常
2.3空指针异常
3、异常的体系结构
4、异常的分类
4.1编译时异常(CheckedException)
4.2运行时异常(UncheckedException)
二、异常的处理
1、防御式编程
1.1事前防御型
1.2事后认错型
2、异常的抛出-throw
3、异常的声明--throws
一、异常的概念与体系结构
1、异常的概念
异常是在程序执行过程中发⽣的⼀种特殊情况或错误状态。它打断了程序的正常流程,需要特别处理。
在日常开发中,程序员绞尽脑汁将代码写的尽善尽美,在程序运⾏过程中,难免会出现⼀些奇奇怪怪的问题。有时通过代码很难去控制,如:数据格式不对、网络不通畅、内存报警等。
在Java中,将程序执行过程中发生的不正常行为称为异常。
2、之前写代码时经常遇到的异常
2.1算术异常
public static void main(String[] args) {System.out.println(10 / 0);}Exception in thread "main" java.lang.ArithmeticException: / by zeroat LibrarySystem.main(LibrarySystem.java:97)
2.2数组越界异常
public static void main(String[] args) {int[] array = {1, 2, 3};System.out.println(array [100]);}Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 100out of bounds for length 3at LibrarySystem.main(LibrarySystem.java:98)
2.3空指针异常
public static void main(String[] args) {int[] array = null;System.out.println(array.length);}Exception in thread "main" java.lang.NullPointerException: Cannot read the array length because "array" is nullat LibrarySystem.main(LibrarySystem.java:98)
从上述过程中可以看到,java中不同类型的异常,都有与其对应的类来进行描述。
3、异常的体系结构
异常种类繁多,为了对不同异常或者错误进行很好的分类管理,Java内部维护了⼀个异常的体系结构:
在图中可以看出:
(1)Throwable:是异常体系的顶层类,而Error和Exception是他的两个子类
(2)Error:指的是Java虚拟机无法解决的问题(一旦发生,回天乏术)
(3)Exception:异常产生后程序员可以通过代码进行处理,使程序继续执行。
简单介绍每个错误:
(1)StackOverflowError(栈溢出错误==>栈被耗尽)
(2)OutOfMemoryError((堆)内存不足错误==>内存泄漏;加载数据量过大;创建的容器的容量过大)
(3)ClassNotFoundException(类未查找到异常==>缺少第三方库的JAR文件;类名拼写错误)
(4)lOException(输入输出异常==>文件找不到、网络连接中断、磁盘已满等)
(5)FileNotFoundException(文件未找到异常==>试图打开一个指定路径不存在的文件)
(6)RuntimeException(运行时异常==>程序逻辑错误)
(7)NullPointerException(空指针异常==>使用null,容易越界等)
(8)ArithmeticException(算数异常==>整数除以零等)
(9)ClassCastException(类转换异常==>错误的强制类型转换)
4、异常的分类
异常可能在编译时发生,也可能在程序运行时发生,根据发生的时机不同,可以将异常分为不同的类别。
4.1编译时异常(CheckedException)
在程序编译期间发生的异常,称为编译时异常,也称为受检查异常。
public class Person {private String name;private String gender;int age;// 想要让该类⽀持深拷⻉,覆写Object类的clone⽅法即可@Overridepublic Person clone() {return (Person)super.clone();}}编译时报错:
Error:(17, 35) java: 未报告的异常错误java.lang.CloneNotSupportedException;
必须对其进⾏捕获或声明以便抛出
以下几个异常属于编译时异常
(1)lOException(输入输出异常==>文件找不到、网络连接中断、磁盘已满等)
(2)FileNotFoundException(文件未找到异常==>试图打开一个指定路径不存在的文件)
(3)SQLException(数据库访问相关的异常==>SQL语法错误;数据库连接失败;表或字段不存在;约束冲突等)
(4)ClassNotFoundException(类未查找到异常==>缺少第三方库的JAR文件;类名拼写错误)
(5)CloneNotSupportedException(调用Object的clone()方法克隆一个对象,但没有实现Cloneable接口)
(6)EOFException(输入操作过程中意外到达文件或流的末尾==>使用ObjectInputStream读取对象时,文件已读完)
(7)UnknownHostException(无法确定主机的IP地址(主机名解析失败))
(8)MalformedURLException(创建了一个格式错误的URL)
(9)ParseException(解析字符串失败==>使用SimpleDateFormat.parse()方法将一个不符合格式的字符串解析为日期对象)
4.2运行时异常(UncheckedException)
在程序执行期间发生的异常,称为运行时异常,也称为非受检查异常
以下几个异常属于运行时异常
(1)NullPointerException(空指针异常==>使用null,容易越界等)
(2)ArrayIndexOutOfBoundsException(数组索引越界异常==>循环条件错误或索引计算错误)
(3)ClassCastException (类转换异常==>在强制转换前没有进行类型检查)
(4)IllegalArgumentException (非法参数异常==>方法参数验证不足)
(5)NumberFormatException (数字格式异常==>字符串包含非数字字符)
(6)ArithmeticException(算术异常==>整数除以零)
(7)IllegalStateException(非法状态异常==>对象状态不符合方法执行的要求)
(8)IndexOutOfBoundsException(索引越界异常)
(9)StringIndexOutOfBoundsException(字符串索引越界==>调用String的charAt(index)方法时索引越界)
(10)NegativeArraySizeException(数组大小为负异常==>尝试用负数创建数组)
#注:编译时出现的语法错误不能称之为异常,那属于错误
二、异常的处理
1、防御式编程
错误在代码中是客观存在的.因此我们要让程序出现问题的时候及时通知程序猿
1.1事前防御型
LBYL:(Look Before You Leap)在操作之前就做充分的检查
boolean ret = false;
ret = 登陆游戏();
if (!ret) {处理登陆游戏错误;return;
}
ret = 开始匹配();
if (!ret) {处理匹配错误;return;
}
ret = 游戏确认();
if (!ret) {处理游戏确认错误;return;
}
ret = 选择英雄();
if (!ret) {处理选择英雄错误;return;
}
ret = 载⼊游戏画⾯();
if (!ret) {处理载⼊游戏错误;return;
}
......
缺点:正常流程和错误处理流程代码混在⼀起,代码整体显的比较混乱。
1.2事后认错型
EAFP:(It's Easier to Ask Forgiveness than Permission) "事后获取原谅比事前获取许可更容易".也就是先操作,遇到问题再处理
try {登陆游戏();开始匹配();游戏确认();选择英雄();载⼊游戏画⾯();...} catch (登陆游戏异常) {处理登陆游戏异常;} catch (开始匹配异常) {处理开始匹配异常;} catch (游戏确认异常) {处理游戏确认异常;} catch (选择英雄异常) {处理选择英雄异常;} catch (载⼊游戏画⾯异常) {处理载⼊游戏画⾯异常;}......
优点:正常流程和错误流程是分离开的,程序员更关注正常流程,代码更清晰,容易理解代码 异常处理的核心思想就是EAFP。
在Java中,异常处理主要的5个关键字:throw、try、catch、finally、throws。
2、异常的抛出-throw
在编写程序时,如果程序中出现错误,此时就需要将错误的信息告知给调⽤者,如:参数检测。 在Java中,可以借助throw关键字,抛出⼀个指定的异常对象,将错误信息告知给调用者。
具体语法如下:
throw new XXXException("异常产⽣的原因");
例:实现一个获取数组中任意位置元素的方法
public static int getElement(int[] array, int index){if(null == array){throw new NullPointerException("传递的数组为null");}if(index < 0 || index >= array.length){throw new ArrayIndexOutOfBoundsException("传递的数组下标越界");}return array[index];}public static void main(String[] args) {int[] array = {1,2,3};getElement(array, 3);}
#注:
(1)throw必须写在方法体内部
(2)抛出的对象必须是Exception或者Exception的子类对象
(3)如果抛出的是RunTimeException或者RunTimeException的子类,则可以不用处理,直接交给JVM来处理
(4)如果抛出的是编译时异常,用户必须处理,否则无法通过编译
(5)异常⼀旦抛出,其后的代码就不会执行
3、异常的声明--throws
throws 关键字用于在方法声明中列出该方法可能抛出的异常,它告诉调用者这个方法可能会抛出某些异常,调用者需要处理这些异常。使用 throws 实际上是将异常的处理责任转移给了调用该方法的代码。
具体语法如下:
修饰符 返回值类型 ⽅法名(参数列表) throws 异常类型1,异常类型2...{}
例:加载指定的配置⽂件config.ini
public class Config {File file;/*FileNotFoundException : 编译时异常,表明⽂件不存在 此处不处理,也没有能⼒处理,应该将错误信息报告给调⽤者,让调⽤者检查⽂件名字是否给错误了*/public void OpenConfig(String filename) throws FileNotFoundException{if(filename.equals("config.ini")){throw new FileNotFoundException("配置⽂件名字不对");} // 打开⽂件}public void readConfig(){}}
#注:
(1)throws必须跟在方法的参数列表之后
(2)声明的异常必须是Exception或者Exception的子类
(3)方法内部如果抛出了多个异常,throws之后必须跟多个异常类型,之间⽤逗号隔开,如果抛出多个异常类型具有父子关系,直接声明父类即可。
public class Config {File file;// FileNotFoundException 继承⾃ IOException public void OpenConfig(String filename) throws IOException{if(filename.endsWith(".ini")){throw new IOException("⽂件不是.ini⽂件");}if(filename.equals("config.ini")){throw new FileNotFoundException("配置⽂件名字不对");}// 打开⽂件}public void readConfig(){}}
(4)调用声明抛出异常的方法时,如果该异常是编译时异常/受查异常时,调用者必须对该异常进行处理,或者继续使用throws抛出
public static void main(String[] args) throws IOException {Config config = new Config();config.openConfig("config.ini");}
将光标放在抛出异常方法上,alt+Insert快速处理:
由于内容较多,会分为多篇讲解,预知后续内容,请看后续博客!!!