异常处理(6)

  1. 异常概述 2. 举例 3. 异常的处理机制 4. final finally finalize区别 5. 自定义异常(开发中常用) 6. 总结异常中的关键字

1. 异常概述

定义

程序执行过程中由代码产生的一种错误。
异常在java中以的形式存在,每一个异常类都可以创建异常对象。

作用

增强程序的健壮性。

体系结构

Throwable类是Java异常体系结构中的根类,有Error类(系统错误类)和Exception类(异常类)。

分类别称
编译时异常:

受检异常:CheckedException
受控异常

Exception的直接子类(除了RuntimeException类及其子类)
编译时异常,要求程序员在编写程序阶段必须预先对这些异常进行处理,如果不处理编译器报错,因此得名编译时异常

运行时异常:

未受检异常:UnCheckedException
非受控异常

RuntimeException类及其子类Error类属于Runtime异常

所有异常都是在运行阶段发生的。因为只有程序运行阶段才可以 new对象。因为异常的发生就是new异常对象。

编译时异常和运行时异常的区别

编译时异常发生概率较高,需要在运行之前对其进行预处理
运行时异常发生概率较低,没必要提前进行预处理。

2. 举例

public class ExceptionTest01 {
public static void main(String[] args) {
int a = 10;
int b = 0;
//1
int c = a / b;
System.out.println(a + “/” + b + “=” + c);
//2
System.out.println(100 / 0);
}
}

实际上JVM在执行到1的时候,会new异常对象:
new ArithmeticException(“/ by zero”);
并且JVM将new的异常对象抛出,打印输出信息到控制台了。
运行到2也会创建一个:ArithmeticException类型的异常对象。

public class ExceptionTest02 {
public static void main(String[] args) {
System.out.println(100 / 0);
// 这里的HelloWorld没有输出,没有执行。
System.out.println(“Hello World!”);
}
}

程序执行到System.out.println(100 / 0);
此处发生ArithmeticException 异常,底层 new 了一个ArithmeticException异常对象,然后抛出了。
由于是 main方法 调用了100 / 0,所以这个异常ArithmeticException抛给了main方法。
main方法没有处理,将这个异常自动抛给了 JVM。JVM最终终止程序的执行。
此时System.out.println(“Hello World!”);并不会执行。

注意:
ArithmeticException 继承 RuntimeException,属于运行时异常。在编写程序阶段不需要对这种异常进行预先的处理。

3. 异常的处理机制

3.1 声明抛出异常子句 throws

在方法声明的位置上使用 throws 关键字抛出,throws上报给方法调用者(推卸责任:调用者知道)
public class ExceptionTest04 {
public static void main(String[] args) throws ClassNotFoundException {
doSome();
}
public static void doSome() throws ClassNotFoundException{
System.out.println(“doSome!!!”);
}
}

3.2 异常的捕获与处理 try…catch

这个异常不会上报,自己把这个事儿处理了。
public class ExceptionTest04 {
public static void main(String[] args) {
try {
doSome();
} catch (ClassNotFoundException e) {
e.printStackTrace();//这个分支中可以使用e引用,e引用保存的内存地址是那个new出来异常对象的内存地址。
}
}
public static void doSome() throws ClassNotFoundException{
System.out.println(“doSome!!!”);
}
}

注意

  1. 只要异常没有捕捉,采用上报的方式,此方法的 后续代码不会执行。
  1. try语句块中的某一行出现异常,该行 后面的代码不会执行。
    try…catch捕捉异常之后,后续代码可以执行。
  2. 异常发生之后,如果我选择了上抛,抛给了我的调用者,调用者需要对这个异常继续处理,那么调用者处理这个异常同样有两种处理方式。
  3. 一般不建议在main方法上使用throws,因为这个异常如果真正的发生了,一定会抛给JVM。JVM只有终止。
  4. 一般main方法中的异常建议使用try…catch进行捕捉。

3.3 抛出异常 throw

throw new Exception(“异常信息”);

3.4 深入try…catch

  1. catch后面的小括号中的类型可以是 具体的异常类型,也可以是该异常类型的 父类型。
  2. catch可以写多个。建议catch的时候,精确的一个一个处理。这样有利于程序的调试。
  3. catch写多个的时候,从上到下,必须遵守 从小到大。

try {
FileInputStream fis = new FileInputStream(“D:\Javabean.docx”);
} catch(FileNotFoundException e) {
System.out.println(“文件不存在!”);
}
等同于
try {
FileInputStream fis = new FileInputStream(“D:\Javabean.docx”);
} catch(Exception e) {// 多态:Exception e = new FileNotFoundException();
System.out.println(“文件不存在!”);
}

try {
FileInputStream fis = new FileInputStream(“D:\Javabean.docx”);
fis.read();
} catch(IOException e){
System.out.println(“读文件报错了!”);
} catch(FileNotFoundException e) {
System.out.println(“文件不存在!”);
}

  1. JDK8的新特性:
    catch() 异常间可以自小到大用 | 分割

try {
//创建输入流
FileInputStream fis = new FileInputStream(“D:\Javabean.docx”);
// 进行数学运算
System.out.println(100 / 0); // 这个异常是运行时异常
} catch(FileNotFoundException | ArithmeticException | NullPointerException e) {
System.out.println(“文件不存在?数学异常?空指针异常?都有可能!”);
}

  1. 异常两个重要方法
    String getMessage() 返回异常的详细消息字符串
    void printStackTrace() 追踪堆栈异常信息(采用异步线程)

  2. finally字句

  3. 在finally子句中的代码是最后执行的,并且是一定会执行的,即使try语句块中的代码出现了异常。

  4. finally子句必须和try一起出现,不能单独编写。

  5. 通常在finally语句块中完成 资源的释放/关闭。

public class ExceptionTest10 {
public static void main(String[] args) {
FileInputStream fis = null; // 声明位置放到try外面。这样在finally中才能用。
try {
fis = new FileInputStream(“D:\Javabean.docx”);
String s = null;
// 这里一定会出现空指针异常!
s.toString();
System.out.println(“hello world!”);
// 流使用完需要关闭,因为流是占用资源的。
// 即使以上程序出现异常,流也必须要关闭!
// 放在这里有可能流关不了。
//fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch(IOException e){
e.printStackTrace();
} catch(NullPointerException e) {
e.printStackTrace();
} finally {
System.out.println(“hello 浩克!”);
// 流的关闭放在这里比较保险。
// finally中的代码是一定会执行的。
// 即使try中出现了异常!
if (fis != null) { // 避免空指针异常!
try {
// close()方法有异常,采用捕捉的方式。
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

  1. try和finally联用,没有catch

public class ExceptionTest11 {
public static void main(String[] args) {
try {
System.out.println(“try…”);
return;
} finally {
System.out.println(“finally…”);
}
// 这里不能写语句,因为这个代码是无法执行到的。
//System.out.println(“Hello World!”);
}
}

以下代码的执行顺序:

  1. 先执行try…
  1. 再执行finally…
  2. 最后执行 return (return语句只要执行方法必然结束。)

注意:

try不能单独使用。
try finally可以联合使用。
放在finally语句块中的代码是一定会执行的

  1. finally子句失效

System.exit(0); 只有这个可以治finally。

java语法规则(有一些规则是不能破坏的,一旦这么说了,就必须这么做!):
java中有一条这样的规则:

  1. 方法体中的代码必须遵循自上而下顺序依次逐行执行(亘古不变的语法!)
  2. return语句一旦执行,整个方法必须结束(亘古不变的语法!)

4. final finally finalize区别

细节
final关键字final修饰的类无法继承;final修饰的方法无法覆盖;final修饰的变量不能重新赋值。
finally关键字finally 和try一起联合使用。finally语句块中的代码是必须执行的。
finalize标识符是一个Object类中的方法名。这个方法是由垃圾回收器GC负责调用的。

5. 自定义异常(开发中常用)

SUN公司提供的JDK内置的异常肯定是不够的用的。在实际的开发中,有很多业务,这些业务出现异常之后,JDK中都是没有的,是和业务挂钩的,因此需要自定义异常。

5.1 自定义异常步骤

第一步:编写一个类继承 Exception 或者 RuntimeException.
第二步:提供两个构造方法,一个无参数的,一个带有String参数的。

自定义异常:栈操作异常
public class StackOperationException extends Exception{
public MyStackOperationException(){
}
public MyStackOperationException(String s){
super(s);
}
}

5.2 方法覆盖时遗留的问题

重写之后的方法不能比重写之前的方法抛出更多(更宽泛)的异常,可以更少。
class Animal {
public void doSome(){}
public void doOther() throws Exception{}
}

class Cat extends Animal {
// 编译正常。
public void doSome() throws RuntimeException{}

// 编译报错。
public void doSome() throws Exception{}

// 编译正常。
public void doOther() {}

// 编译正常。
public void doOther() throws Exception{}

// 编译正常。
public void doOther() throws NullPointerException{}
}

注意:
一般不会这样考虑,方法覆盖复制一份,然后重写就好了。

6. 总结异常中的关键字

异常捕捉:
try
catch
finally
throws 在方法声明位置上使用,表示上报异常信息给调用者。
throw 手动抛出异常

public void pop() throws StackOperationException {
if(index < 0){
throw new MyStackOperationException(“弹栈失败,栈已空!”);//手动抛出异常
}
}
该方法index < 0时手动抛出异常,然后在方法里没有处理,上报给调用者,让调用者处理!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值