提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
没什么用的前言
try-catch-finally中哪个部分可以省略
catch和finally可以省略其中的一个,catch和finally不能同时省略,省略了catch块发生异常时就不会捕获异常了,所以不推荐
Error和Exception的区别
在使用计算机语言进行项目开发的过程中,即使程序员把代码写得尽善尽美,在系统的运行过程中仍然会遇到一些问题,因为很多问题不是靠代码能够避免的。比如: 客户输入数据的格式, 读取文件是否存在, 网络是否始终保持通畅等等。
-
Error: Java虚拟机无法解决的严重问题,常是不可恢复的,比如内存溢出, JVM系统内部错误、 资源耗尽等程序无法处理
-
Exception:表示需要捕获,程序能处理的异常,是一种设计或实现问题。
-
运行时异常,虚拟机运行程序时可能发生的异常,通常只要程序设计没有问题就不会发生。
java.lang.RuntimeException类及它的子类都是运行时异常。对于这类异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。
-
编译时异常,编译器要求方法必须捕获或声明抛出可能发生的受检查异常,也就是说编译器在编译时能检查到的异常
-
常见的异常类
受检查异常主要有
受检查异常 | 说明 |
---|---|
ClassNotFoundException | 没有找到类 |
IllegalAccessException | 访问类被拒绝 |
InstantiationException | 试图创建抽象类或接口的对象 |
InterruptedException | 线程被另一个线程中断 |
NoSuchFieldException | 请求的域不存在 |
NoSuchMethodException | 请求的方法不存在 |
ReflectiveOperationException | 与反射有关的异常的超类 |
IO异常 |
运行时异常主要有
运行时异常 | 说明 |
---|---|
ArithmeticException | 算术错误异常,如以零做除数 |
ArraylndexOutOfBoundException | 数组索引越界 |
ArrayStoreException | 向类型不兼容的数组元素赋值 |
ClassCastException | 类型转换异常 |
IllegalArgumentException | 使用非法实参调用方法 |
lIIegalStateException | 环境或应用程序处于不正确的状态 |
lIIegalThreadStateException | 被请求的操作与当前线程状态不兼容 |
IndexOutOfBoundsException | 某种类型的索引越界 |
NullPointerException | 尝试访问 null 对象成员,空指针异常 |
NegativeArraySizeException | 再负数范围内创建的数组 |
NumberFormatException | 数字转化格式异常,比如字符串到 float 型数字的转换无效 |
TypeNotPresentException | 类型未找到 |
指针:指针存放的是内存地址
空指针:所以当指针不指向任何内存地址时,就叫做空指针,例如:int[] array = null
**空指针异常:**就是一个指针不指向任何内存地址,但是你还调用他了
int[] array = null; System.out.println(array[0]);
这个时候原本array数组是个空指针,没有创建新的对象,在调用这个数组的时候就会产生空指针异常的错误!
异常处理机制一:try-catch-finally
在编写程序时,经常要在可能出现错误的地方加上检测的代码,如进行x/y运算时,要检测分母为0,数据为空,输入的不是数据而是字符等。过多的if-else分支会导致程序的代码加长、臃肿,可读性差。因此采用异常处理机制。使得程序简洁、优雅, 并易于维护。
异常对象的生成
-
由虚拟机自动生成:程序运行过程中,虚拟机检测到程序发生了问题,如果在当前代码中没有找到相应的处理程序,就会在后台自动创建一个对应异常类的实例对象并抛出——自动抛出
-
由开发人员手动创建: Exception exception = new ClassCastException();——创建好的异常对象不抛出对程序没有任何影响,和创建一个普通对象一样。
捕获(catch)异常
如果一个方法内抛出异常, 该异常对象会被抛给调用者方法中处理。
如果异常没有在调用者方法中处理, 它继续被抛给这个调用方法的上层方法。
这个过程将一直继续下去, 直到异常被处理。这一过程称为捕获(catch)异常。
如果一个异常回到main()方法, 并且main()也不处理, 则程序运行终止
异常处理是通过try-catch-finally语句实现的。
- try
捕获异常的第一步是用try{…}语句块选定捕获异常的范围, 将可能出现异常的代码放在try语句块中。在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配。 一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常处理,一旦处理完成就跳出当前的try-catch结构(在没有写finally的情况下)。继续执行其后的代码。
在try结构中声明的变量,不能在try结构外被调用。
- catch (Exceptiontype e)
在catch语句块中是对异常对象进行处理的代码。 每个try语句块可以伴随一个或多个catch语句, 用于处理可能产生的不同类型的异常对象。catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓,如果异常类型满足子父类的关系,则要求子类一定要声明在父类的上面,否则报错。
- finally
捕获异常的最后一步是通过finally语句为异常处理提供一个统一的出口,使得在控制流转到程序的其它部分以前,能够对程序的状态作统一的管理。finaly中声明的是一定会被执行的代码,即使catch中出现了异常,try中有return语句,catch中有return语句等情况。finally语句和catch语句是任选的。像数据库连接,输入输出流,网络编程socket等资源,JVM是不能自动回收的,我们需要手动的进行资源的释放。此时的资源的释放,就需要声明在finally中。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1SHUeuhG-1682473808799)(C:\Users\Joshua.TV\Pictures\webPhoto_Typora\watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW5nanVueWVz,size_16,color_FFFFFF,t_70-16824250500663.png)]
注意:
如果明确知道产生的是何种异常, 可以用该异常类作为catch的参数;也可以用其父类作为catch的参数。比 如 : 可 以 用ArithmeticException 类 作 为 参 数 的 地 方 , 就 可 以 用RuntimeException类作为参数, 或者用所有异常的父类Exception类作为参数。但不能是与ArithmeticException类无关的异常, 如NullPointerException(catch中的语句将不会执行) 。
使用try-cathch-finally处理编译时异常,使得程序在编译时不在报错,但在运行时,仍有可能报错。相当我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。
try-catch-finally结构可以相互嵌套。
捕获异常的有关信息:
与其它对象一样,可以访问一个异常对象的成员变量或调用它的方法。
getMessage() 获取异常信息,返回字符串
printStackTrace() 获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7if0Bfx9-1682473808801)(C:\Users\Joshua.TV\Pictures\webPhoto_Typora\watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW5nanVueWVz,size_16,color_FFFFFF,t_70-16824251258265.png)]
异常处理机制二:throws +异常类型
如果一个方法(中的语句执行时)可能生成某种异常, 但是并不能确定如何处理这种异常, 则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
在方法声明中用throws语句可以声明抛出异常的列表, throws后面的异常类型可以是方法中产生的异常类型, 也可以是它的父类。一旦方法体执行时,出现异常,仍会在异常代码处,生成一个异常类的对象,此对象满足throws后异常类型是,就会被抛出。异常代码后续的代码,就不会执行。
public void method() {
try {
test3();//method方法调用,method方法捕获处理
} catch (FileNotFoundException e) {
e.printStackTrace();//打印栈轨迹
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void test3() throws FileNotFoundException,IOException {
File file =new File("heool.txt");//new一个文件对象
FileInputStream fis = new FileInputStream(file);//new一个文件输入流对象
int data = fis.read();//把fis读到的结果返回给data
while(data != -1) {//只要不等于-1就一直循环,或者说只有等于-1才退出循环
System.out.println((char)data);//打印data
data = fis.read();//重新读fis把结果返回给data
}
fis.close();//关闭输入流
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VelnB709-1682473808801)(C:\Users\Joshua.TV\Pictures\webPhoto_Typora\watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW5nanVueWVz,size_16,color_FFFFFF,t_70-16824673138777.png)]
重写方法声明抛出异常的原则
重写方法不能抛出比被重写方法范围更大的异常类型(子类方法抛出的异常不能是父类同名方法抛出的父类)。 在多态的情况下,
对methodA()方法的调用-异常的捕获按父类声明的异常处理。
public class A {
public void methodA() throws IOException {
……
} }
public class B1 extends A {
public void methodA() throws FileNotFoundException {//父类A怎么处理的就怎么处理
……
} }
public class B2 extends A {
public void methodA() throws Exception { //报错
……
} }
如何选择try-catch和throws
如果父类中被重写的方法中没有throws方式处理异常,则子类重写的方法中也不能使用throws,意味如果子类重写的方法中有异常,必须使用try-catch。
执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的,我们建议这几个方法使用throws的方式进行处理。而执行的方法a可以考虑使用try-catch
手动抛出异常
java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出, 也可根据需要使用人工创建并抛出。
首先要生成异常类对象, 然后通过throw语句实现抛出操作(提交给Java运行环境)。
IOException e = new IOException();
throw e;
可以抛出的异常必须是Throwable或其子类的实例。 下面的语句在编译时将会产生语法错误:
throw new String(“want to throw”);
public class ExceptionTest3 {
public static void main(String[] args) {
try {
Student stu=new Student();
stu.register(-1003);//调用了可能抛异常的方法。
System.out.println(stu);//重写的了tostring,输出的是id=-1003
} catch (Exception e) {
System.out.println(e.getMessage());//打印exception的参数,输入的数据不合法
}
}
}
class Student{
private int id;
public void register(int id) throws Exception {
if(id>0) {
this.id =id;
}else {
//System.out.println("输入的id不合法");
//手动抛出异常
//throw new RuntimeException("你输入的数据不合法");
throw new Exception("输入的数据不合法");
}
}
@Override//这里重写的是object的tostring方法
public String toString() {
return "Student [id=" + id + "]";
}
}
用户自定义异常类
一般地,用户自定义异常类都是RuntimeException的子类。
自定义异常类要求
- 通常需要编写几个重载的构造器。
- 需要提供全局常量:serialVersionUID
- 通过throw抛出。
- 最重要的是异常类的名字,当异常出现时,可以根据名字判断异常类型。
用户自定义异常类MyException,用于描述数据取值范围错误信息。用户自己的异常类必须继承现有的异常类。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yoCZLIPq-1682473808803)(C:\Users\Joshua.TV\Pictures\webPhoto_Typora\watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW5nanVueWVz,size_16,color_FFFFFF,t_70-16824674150759.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dlCeXkX1-1682473808804)(C:\Users\Joshua.TV\Pictures\webPhoto_Typora\watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW5nanVueWVz,size_16,color_FFFFFF,t_70-168246742445111.png)]
总结
没什么好总结的