异常

一、异常的分类

在这里插入图片描述

二、异常的处理

针对异常,JVM的处理方式:
一旦遇到了程序出现了问题,就会把问题的类名,错误原因,错误的位置等信息打印在控制台,以便我们纠错。同时JVM会自动从出现问题处将程序终止掉,导致程序无法继续向下执行。
eg:

public class TestTryCatch {
	public static void main(String[] args) {
		System.out.println("程序开始了");
		String str = null;
		System.out.println(str.length());
		System.out.println("程序结束了");
}
}

在这里插入图片描述

为了让其他没问题的程序继续执行可以采用以下做法:
使用try——catch语句对异常进行捕获

public class TestTryCatch {
   public static void main(String[] args) {
   	System.out.println("程序开始了");
   	try{
   	String str = null;
   	System.out.println(str.length());
   	}catch(NullPointerException e){
   		System.out.println("出现了空指针");
   	}
   	System.out.println("程序结束了");
}
}
   

在这里插入图片描述

<2.1.1> java异常处理机制中的try——catch语法:

  • try{
  • 代码片段
  • }catch(xxxException e){
  • 捕获try代码片段中出现的xxxException
  • 后的处理手段
  • }

注意事项了解一下:
1.在try代码块中,发生异常语句后面的代码是不会被执行的。

2.catch可以定义多个,针对不同的异常有不同的处理手段时,可以分别捕获这些异常。

3.应当有一个好习惯,在最后一个catch中捕获Exception,尽量避免因为一个 未捕获的异常导致程序中断。捕获顺序应是子类型异常在上面先捕获,父类型异常在下后捕获。

<2.1.2> finally

在程序中,有时候我们希望有些语句无论程序是否发生异常都要执行,这时就可以在
try-catch语句后加一个finally代码块。

@Test
	public void testFinallyDemo1(){
		System.out.println("程序開始了");
		try{
			String str = null;
			System.out.println(str.length());
		}catch(Exception e){
			System.out.println("程序出错了");
		}finally{
			System.out.println("finally中的代码运行了");
		}
		System.out.println("程序结束了");
	}

在这里插入图片描述
finally中需要注意的:

  • finally块是异常捕获机制中的最后一块。
  • finally可以直接跟在try后面或者最后一个catch之后。
  • finally可以保证只要程序执行到try语句块中,无论try语句块中的代码是否抛出异常,finally块中的代码都必定执行。
  • 通常会将无论是否出现异常都要运行的代码放在finally中确保运行,比如IO操作中的关闭流。
  • 有一点需要注意一下,finally中的代码有一种情况下是不会执行的,那就是在
    try-catch中执行了System.exit(0)语句。System.exit(0)表示退出当前的Java虚拟机,Java虚拟机停止了,任何代码都不能再执行了。

<2.1.3> throws

如果调用自己的方法,我们很清楚该方法可能会发生的异常。试想一下,如果去调用一个别人写的方法时,是否能知道别人写的方法是否会有异常呢?这是很难做出判断的。针对这种情况,Java中允许在方法的后面使用throws关键字对外声明该方法有可能发生的异常,这样调用者在调用时,就明确的知道方法有异常,并且需要调用者对异常进行处理,否则编译无法通过。
eg:
在这里插入图片描述
从该例可以看出,当在方法声明抛出一个异常时,在主函数中调用时,必须对该异常进行处理,否则编译不会通过。一般在主函数调用声明异常的方法时,选择对其进行
try-catch处理。
在这里插入图片描述
注意事项:
派生类在继承超类时会重写其方法,那么在重写超类中含有throws声明异常抛出的方法时,对throws的重写规则:

  • 可以不再抛出任何异常
  • 可以仅抛出父类方法抛出的部分异常
  • 可以抛出父类方法抛出异常的子类型异常
  • 不允许抛出父类方法抛出异常的父类型异常
  • 不允许抛出额外异常
public class ThrowsDemo {
    public void dosome() throws IOException,AWTException{
    	
    }
class Son extends ThrowsDemo{
//	public void dosome() throws IOException,AWTException{
//		
//	}
	/*
	 * 可以不再抛出任何异常
	 */
//	public void dosome(){
//		
//	}
	/*
	 * 可以仅抛出父类方法抛出的部分异常
	 */
//	public void dosome() throws IOException{
//		
//	}
	/*
	 * 可以抛出父类方法抛出异常的子类型异常
	 */
//	public void dosome() throws FileNotFoundException{
//		
//	}
	/*
	 * 不允许抛出额外异常
	 */
	//public void dosome() throws SQLException{}  SQLException并非继承自Throwable,而是继承自 java.lang.Exception。
	/*
	 * 不允许抛出父类方法抛出异常的父类型异常
	 */
//	public void dosome() throws Exception{}
}

<2.1.4> throw

当不满足业务逻辑要求时,可以主动抛异常。当一个方法中使用throw抛出一个异常时,就应该在当前方法上使用throws声明该异常的抛出,通知调用者在调用当前方法时要处理异常(RuntimeException除外)否则编译不通过。
eg:

/*
 * 使用当前类测试异常的抛出 
 */
public class Person {
     private  int age;

	/**
	 * @return the age
	 */
	public int getAge() {
		return age;
	}

	/**
	 * @param age the age to set
	 */
	public void setAge(int age) throws Exception{
		if(age<0||age>100){
			throw new Exception("年龄不合法");
		}
		this.age = age; 
	}
}

@Test
public void testThrowDemo(){
	System.out.println("程序开始了");
	Person p = new Person();

		try {
			p.setAge(100000);
		} catch (Exception e) {
			e.printStackTrace();
		}
	System.out.println("此人年龄:"+p.getAge());
	System.out.println("程序结束了");
}

在这里插入图片描述

三、自定义异常

JDK中定义了大量的异常类,虽然这些异常类可以描述编程时出现的大部分异常情况,但是在程序开发中有时可能需要描述程序中特有的异常情况。为了解决这个问题,在java中允许用户自定义异常,但自定义异常必须继承自Exception类或其他子类。

/**
 * 年龄不合法异常
 * 
 * 自定义异常通常用来说明某些业务逻辑错误
 */
public class IllegalAgeException extends Exception{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public IllegalAgeException() {
		super();
		// TODO Auto-generated constructor stub
	}

	public IllegalAgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
		// TODO Auto-generated constructor stub
	}

	public IllegalAgeException(String message, Throwable cause) {
		super(message, cause);
		// TODO Auto-generated constructor stub
	}

	public IllegalAgeException(String message) {
		super(message);
		// TODO Auto-generated constructor stub
	}

	public IllegalAgeException(Throwable cause) {
		super(cause);
		// TODO Auto-generated constructor stub
	}
    
}
注意:在实际开发中,如果没有特殊的要求,自定义的异常类只需继承Exception类
,在构造方法中使用supper()语句调用Exception的构造方法即可。

既然自定义了异常,那么该如何使用呢?这时就需要用到throw关键字,throw关键字用于在方法中声明抛出异常的实例对象。

  • 语法格式:
  • throw Exception 异常对象
    eg:

/*
 * 使用当前类测试异常的抛出 
 */
public class Person {
     private  int age;

	/**
	 * @return the age
	 */
	public int getAge() {
		return age;
	}

	/**
	 * @param age the age to set
	 */
	public void setAge(int age) throws IllegalAgeException{
		if(age<0||age>100){
			throw new IllegalAgeException("年龄不合法");
		}
		this.age = age; 
	}
}

测试异常的抛出:
因为首先我们自定义了异常类,且在Person类中使用了throw关键字在方法中向调用者抛出了IllegalAgeException异常,所以在调用该方法p.setAge()时,调用者必须处理异常,否则编译不通过。


/*
 * 测试异常的抛出
 */
public class ThrowDemo {
@Test
public void testThrowDemo(){
	System.out.println("程序开始了");
	Person p = new Person();
	
		/*
		 * 当调用一个含有throws声明异常抛出的方法时,编译器要求必须处理这个异常
		 * 而处理方式有两种:
		 * 1.使用try——catch处理该异常
		 * 2.在当前方法上继续声明throws将该异常抛出
		 * 具体如何处理,结合实际业务需求而定。
		 */
		try {
			p.setAge(10);
		} catch (IllegalAgeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	System.out.println("此人年龄:"+p.getAge());
	System.out.println("程序结束了");
}
}

Tips

finally和final的区别:
final,最终的意思。可以修饰类,方法,变量。
修饰类,类不能被继承,但可以继承别人。
修饰方法,方法不能被重写。
修饰变量,变量是常量。

finally
异常处理的一部分。被finally控制的代码块一定会执行。

throw和throws的区别:
throws:

  • 用在方法声明后面,跟的是异常类名
  • 可以跟多个异常类名,用逗号隔开
  • 表示抛出异常,由该方法的调用者来处理
  • throws表示出现异常的一种可能性,并不一定会发生这些异常。

throw:

  • 用在方法体内,跟的是异常对象名
  • 只能抛出一个异常对象名
  • 表示抛出异常,由方法体内的语句处理
  • throw是抛出了异常,执行throw则一定抛出了某种异常
  • 如果throw的是编译时期异常,在方法声明上必须用throws进行标记
  • 如果throw的是运行时期异常,在方法声明上可以用throws进行标记,也可以不用。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值