第十章 Java中的异常机制

10.1 异常类的继承关系与分类

在这里插入图片描述从上图继承关系可知:
1.Throwable 是异常体系的根,它继承自 ObjectThrowable 有两个体系: Error 和 Exception Error 表示严重的错误,程序对此一般无能为力,例如:

  • OutOfMemoryError :内存耗尽(堆内存异常,数组空间开辟过大,程序中对象太多)
  • NoClassDefFoundError :无法加载某个Class
  • StackOverflowError :栈溢出(函数递归)

2. Exception 则是运行时的错误它可以被捕获并处理

某些异常是应用程序逻辑处理的一部分,应该捕获并处理。例如:

  • NumberFormatException :数值类型的格式错误 (将数字字符串进行解析)
  • FileNotFoundException :未找到文件
  • SocketException :读取网络失败

还有一些异常是程序逻辑编写不对造成的,应该修复程序本身。例如:

  • NullPointerException :对某个 null 的对象调用方法或字段
  • ArrayIndexOutOfBoundsException :数组索引越界

3.Exception 又分为两大类:

(1) RuntimeException 以及它的子类

(2)非 RuntimeException(包括 IOException ReflectiveOperationException 等等)

4.Java规定:

  • 必须捕获的异常,包括 Exception 及其子类,但不包括 RuntimeException 及其子类,这种类型的异常称为Checked Exception。
  • 不需要捕获的异常,包括 Error 及其子类RuntimeException 及其子类

5.其他常见异常信息:

  • StringfIndexOutOfBoundsException:字符串角标越界异常 角标不在字符串范围内

  • ArithmeticException: 数学运算异常 非法的数学运算

  • ClassCastException: 类型转换异常 将类进行错误的强制转换

  • InputMismatchException:输入不匹配异常 在输入时输入非法数据

  • ParseException:时间解析异常 非法的时间格式

10.2 捕获异常

Try —catch ----finally

try 块{

  	//可能会有异常发生的代码

}catch(Exception e ){

  	// 当有异常发生的时候,catch块被执行;当没有异常发生的时候 catch块就不执行了

}finally{

  //不管异常是否发生都要执行

}

10.2.1 多catch语句

  可以使用多个 catch 语句,每个 catch 分别捕获对应的 Exception 及其子类。JVM在捕获到异常后,会从上到下匹配 catch 语句,匹配到某个 catch 后,执行 catch 代码块,然后不再继续匹配。

多个 catch 语句只有一个能被执行。例如:

public static void main(String[] args) { 	
	try {
		process1();                              
		process2(); 		
		process3(); 
	} catch (IOException e) { 					
		System.out.println(e); 
	} catch (NumberFormatException e) { 		
		System.out.println(e); 
	} 
}

  存在多个 catch 的时候, catch 的顺序非常重要:子类必须写在前面。例如:

public static void main(String[] args) { 
    try {
        process1(); 
        process2(); 
        process3(); 
    } catch (IOException e) { 
        System.out.println("IO error"); 
    } catch (UnsupportedEncodingException e) { 
        // 永远捕获不到 
        System.out.println("Bad encoding"); 
    } 
}

  对于上面的代码,UnsupportedEncodingException 异常是永远捕获不到的,因为它是IOException 的子类。当抛出 UnsupportedEncodingException 异常时,会被 catch(IOException e) { ... } 捕获并执行。

  正确的写法:把子类放到前面:

public static void main(String[] args) { 
    try {
        process1(); 
        process2(); 
        process3(); 
    } catch (UnsupportedEncodingException e) { 
        System.out.println("Bad encoding"); 
    } catch (IOException e) { 
        System.out.println("IO error"); 
    } 
}

10.2.2 捕获多种异常

  如果某些异常的处理逻辑相同,但是异常本身不存在继承关系,那么就得编写多条 catch 子句:

public static void main(String[] args) { 
    try {
        process1(); 
        process2(); 
        process3(); 
    } catch (IOException | NumberFormatException e) { 
        // IOException或 NumberFormatException 
        System.out.println("Bad input"); 
    } catch (Exception e) { 
        System.out.println("Unknown error"); 
    } 
}

小结:

使用 try … catch … finally 时:

  • 多个 catch 语句的匹配顺序非常重要,子类必须放在前面;

  • finally 语句保证了有无异常都会执行,它是可选的;

  • 一个 catch 语句也可以匹配多个非继承关系的异常。

10.2.3 try-catch-finally中的return

  1. try块中有return关键字时,如果没有finally 则直接返回。
  2. try块中有return 关键字 ,catch块也有return;如果异常时,则作走catch块的return;如果没有异常则走try里return
  3. try块中有returnfinally中也有return; 如果没有异常发生走finally里的return
  4. try块中有return,catch也有return,finally还有return;没异常按照第3条走如果有异常 则按照finally中的返回结果执行
package Demo;

public class ExceptionDemo01 {
	public static void main(String[] args) {
		ExceptionDemo01 testDemo01 = new ExceptionDemo01();
		
		ExceptionDemo01 test = testDemo01.get();
		System.out.println(test);
	}
	
	@SuppressWarnings("finally")
	public ExceptionDemo01 get() {

		int a = 10;
		int b = 0;
		try{
			
			int c = 10/0; 
			System.out.println("444");
			return null;
		}catch(Exception e){
			
			try{
				
				System.out.println("123");
			}catch(Exception ex){
				
			}
			return this;
		
		}finally{
			System.out.println("我是一定要执行的");
			return null;
			
		}
	}
}

*10.2.4 final finally finalize() 有什么区别?

*10.2.5 Thread. sleep()是否会抛出checked exception?(会)

答:
checked exception:指的是编译时异常,该类异常需要本函数必须处理的,用try和catch处理,或者用throws抛出异常,然后交给调用者去处理异常。

runtime exception:指的是运行时异常,该类异常不必须本函数必须处理,当然也可以处理。

Thread.sleep()抛出的InterruptException属于checked exceptionIllegalArgumentException属于Runtime exception

10.2.6 finnally可以单独和哪个一起使用?

try,可以是try-catch;try-catch-finnally;try-finnally。没有catch的时候一定要有finnally!

10.3 抛出异常和声明异常

throw

public static void main(String[] args) {
		//抛出异常throw
		String id;
		
		System.out.println("请输入您的员工编号");
		
		Scanner input = new Scanner(System.in);
		
		id = input.next();
		
		if(id.length() == 6){
			System.out.println("你是一个合格的员工");
		}else{
			throw new IllegalArgumentException("你的id不符合要求,请联系上帝");
		}
	
	}

  throws 声明异常 一般情况下用在你的方法头 。

package P36;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.text.ParseException;

public class ExceptionDemo06 {
    public static void main(String[] args) {

    }
}
class Fu {
    public void show(){}
    public void test(){}
    public void haha() throws IOException, SQLException {}

    public void xixi() throws IndexOutOfBoundsException{}
}
class Zi extends Fu {
    //父类如果没有声明异常,则子类重写的函数不能声明编译时异常
        //如果子类中真要有抛出编译时异常 只能try-catch
//    public void show() throws ParseException {}

    //父类如果没有声明异常,则子类重写的函数可以声明运行时异常
    public void test() throws NullPointerException{}

    //父类如果声明编译时异常,则子类重写的函数可以不声明编译时异常
    //父类如果声明编译时异常,则子类重写的函数声明编译时异常 必须是父类异常或其子类异常或其子类异常的集合
    public void haha() throws FileNotFoundException, InterruptedIOException, SQLWarning {}

    //父类如果声明运行时异常,则子类重写的函数可以不声明运行时异常
    //父类如果声明运行时异常,则子类重写的函数声明运行时异常 必须是父类异常或其子类异常或其子类异常的集合
    public void xixi() throws ArrayIndexOutOfBoundsException,StringIndexOutOfBoundsException{}
}

*10.3.1 throw和throws的区别?(从关键字和用法说区别)

  1. throws用在函数头,throws后跟的是异常类,可以跟多个;
    throw位于函数体内部,后面跟的是异常对象。

  2. throws用来声明异常,主要是声明非运行时异常做检查使用。说明该功能下可能出现的问题,可以给出预先的处理方式;
    throw用来抛出异常,用于抛出一些运行时异常,在代码中可以自定义逻辑,也可以抛出自定义的异常。throw执行之后,后面的代码不再被执行,在代码中可以自定义逻辑,也可以抛出自定义的异常。

  3. throws表现出的是异常的一种可能性,不一定会发生;
    throw抛出了异常,执行了之后一定抛出了异常对象。

  4. 两种方式都只能抛出或可能抛出异常,但是不会处理异常,处理异常由函数上层调用处理

10.4 自定义异常

  Exception,RunTimeException

  用于在自己的框架中描述一些自定义的异常类,展示和Java原有的异常信息不同

实现方案:

   要借助 Exception 和 RunTimeException

public class MyDaoException extends RuntimeException {
	
	static final long serialVersionUID = -7034897190745766939L;
	
	public MyDaoException() {
	  super();
	}
	
	
	public MyDaoException(String message) {
		 super(message);
	}
	
	 public MyDaoException(Throwable cause) {
	        super(cause);
	 }
	
	
	public MyDaoException(String message, Throwable cause) {
		super(message, cause);
	}
	

问题:接口中没有声明异常,而实现的子类覆盖方法时发生了异常,怎么办?

答:无法进行throws声明,只能catch的捕获。万一问题处理不了呢?catch中继续throw抛出,但是只能将异常转换成RuntimeException子类抛出。

10.5 一个代码

public static void main(String[] args) {
        int[] arr = {1,2,3,4,5};
        int num = getNumber(arr,10);
        System.out.println(num);
}
private static int getNumber(int[] arr, int i) {
        //return arr[i];//是由JVM来进行判断的
        //模拟JVM的操作 用手动的判断模拟JVM自动的发现
        if (arr == null) {
            //产生一个空指针异常的问题对象
            //用throw(抛出)关键 将产生的问题告知调用者
            throw new NullPointerException();
            //一旦上述抛出一个问题 此函数立马中断
            //类似于return 正常结束(弹栈)
            //throw非正常结束(中断 强制弹栈 并抛出问题给调用者)
        }
        if (i < 0 || i >= arr.length) {
            //产生一个数组角标越界异常的问题对象
            throw new ArrayIndexOutOfBoundsException();
            //throw new StackOverflowError();
            //PS 一旦出现错误 抛出问题即可 但是最好抛出最相关最精确的问题
        }
        return arr[i];
    }

  getNumber如果发生了问题是直接将问题抛给主函数的,但是主函数也没有处理这个问题,主函数接着将问题抛给调用者JVM。
   JVM不帮你解决 结果就是程序中断了!

JVM-调用main-调用getNumber-getNumber出现异常-抛出给main-main没有处理-抛出传递给JVM-JVM直接给你中断

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值