day18 异常

day18 异常

异常的描述

1.异常:开发过程中发生了一些错误,或者是不正常的情况(可以在代码中进行处理,甚至可以避免)。

2.异常解决的方式:

​ 1. 异常声明或抛出

​ 2. 异常捕获,解决异常

3. 代码终止

3.error:错误,表示代码中发生的比较严重的问题,一般都会去解决,只能去修改代码。比如:内存溢出。

4.体系:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e9x35dmM-1575467332904)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20191204200733601.png)]

Throwable:所有错误和异常的顶层父类

	Error:错误

			RuntimeException:运行时异常(出现了这种异常,代码没有提示你进行处理)

			编译异常

	Exception:异常

5.jvm异常处理机制:发生异常后,谁也不处理,一层一层向上抛出异常,最后抛到jvm处,jvm打印异常信息,代码停止。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lJo9ELRa-1575467332906)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20191204201539209.png)]

6.手动异常处理方式

  1. 异常声明:代码运行过程中(方法中),发生了异常,在方法上进行这个一行的声明动作,作用就是告知方法的调用者,我这个方法运行时,可能有问题,就是为了让方法的调用者进行适当的异常处理。

    注意:如果是运行时异常,不需要声明处理;如果是编译异常,需要声明。

  2. 异常处理:代码运行过程中,发生了异常,在方法内部,可能发生异常的代码,进行处理,处理完毕,代码可以不用停止,继续运行。

  3. (1)try…catch(2)try…catch…finaly(3)try…finaly

异常

1. throw关键字:抛出异常
  1. throw关键字:表示抛出,用于抛出异常

  2. 使用场景:数据合法性验证,或者可能会发生问题

  3. 语法结构:

    throw new 异常()

  4. 注意事项

    (1)throw后每次只能创建出一个异常

    (2)如果代码中有多个异常,那么可多次使用throw进行异常的抛出

    (3)代码中执行到throw,方法中throw之后的代码都不在运行。

public class ThrowException{
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//int[] arr = {2, 5, 4, 9, 7, 1};
		int[] arr = null;
		getElement(arr, 6);
	}

	public static void getElement(int[] arr, int index) {
		//控制数组空指针异常
		if(arr==null||arr.length==0) {
			throw new NullPointerException("数组不能为空,或没有元素");
		}
		//控制数组越界异常
		if(index >= arr.length) {
			throw new ArrayIndexOutOfBoundsException("提供的索引"+index+"在数组中不存在");
		}
		System.out.println(arr[index]);
	}
}

2. throws:声明异常

  1. throws关键字:功能就是进行异常声明,在方法上进行这个异常的声明动作。

  2. 语法结构:

    修饰符 返回值类型 方法名(参数列表) throws 异常1, 异常2,…{

    ​ 方法逻辑

    }

3.throws使用场景

  1. 如果方法内部抛出的是运行时异常,那么可以不声明

  2. 如果方法内部抛出的异常是编译异常,必须声明(或处理)

  1. throws特点:

    (1)throws只是作为异常的声明,作用,通知方法的调用者,方法内部可能会出现异常,提示方法调用者做一个提前处理。

    (2)throws关键字后面可以写多个异常,异常之间使用逗号分隔

    (3)方法中的运行异常,不需要声明,编译异常,需要声明或处理

  2. 代码

/*
 * throws:异常声明
 * */
public class ThrowsException {

	public static void main(String[] args) throws ParseException {
		// TODO Auto-generated method stub
		//int[] arr = {2, 5, 4, 9, 7, 1};
		int[] arr = null;
		getElement(arr, 6);
		dateException();
	}

	public static void dateException() throws ParseException {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		String date = "2019-09-09";
		//将字符串解析成日期
		sdf.parse(date);
	}

	public static void getElement(int[] arr, int index) throws NullPointerException, ArrayIndexOutOfBoundsException{
		//控制数组空指针异常
		if(arr==null||arr.length==0) {
			throw new NullPointerException("数组不能为空,或没有元素");
		}
		//控制数组越界异常
		if(index >= arr.length) {
			throw new ArrayIndexOutOfBoundsException("提供的索引"+index+"在数组中不存在");
		}
		System.out.println(arr[index]);
	}
}

3.throw与throws关键字之间的区别

  1. 定义位置不同:

    (1)throw定义在方法内部

    (2)throws定义在方法上

  2. 功能不同

    (1)throw表示异常的抛出,直接把发生的异常抛出

    (2)throws表示异常的声明,只是给方法的调用者一个提醒

  3. 异常个数不同

    (1)throw每次只能创建和抛出一个异常

    (2)throws可以声明多个异常

Try…catch:异常处理

  1. try:关键字,功能就是对异常信息的检测

    catch:关键字,功能就是捕获异常

  2. 语法结构

try{
// 可能会发生异常的代码

}catch(异常类型 名字){

 // 异常的处理方式

}...finally{

 // 一定会执行的代码

}
  1. try…catch的运行方式
  1. 先执行try中的代码, 如果没有异常发生,将try中的内容执行完毕,代码继续向下运行

  2. 如果try代码中发生了异常, try会将异常进行抛出, 抛给catch代码块, catch进行异常信息的匹配, 如果匹配执行catch代码块中的内容,执行完毕,代码接着try…catch之后继续运行; 如果catch没有将发生的异常正确匹配, 那么异常还是要抛给JVM进行自动处理

  1. 运行代码

    public class TryCatchException {
    
    	public static void main(String[] args) {
    		int i = 5;
    		
    		try {
    			int m = i/0;
    			System.out.println(m);
    		}
    		catch(ArithmeticException e){
    			//System.out.println("除数不能为0");
    			e.printStackTrace();
    		}
    		
    		System.out.println("hello world");
    	}
    }
    

多Catch异常处理

  1. 语法结构

    public class TryCatchException {
    
    	public static void main(String[] args) {
    		int i = 5;
    		
    		try {
    			int m = i/0;
    			System.out.println(m);
    		}
    		catch(ArithmeticException e){
    			//System.out.println("除数不能为0");
    			e.printStackTrace();
    		}
    		
    		System.out.println("hello world");
    	}
    }
    
  2. 运行

    1. 先执行try中的代码块内容,没有异常,还不执行catch,继续代码向下运行
    2. 如果try中出现异常,从出现异常的代码位置直接跳转到catch语句, 将try中的异常信息依次(从上到下)与catch中的异常信息进行匹配, 匹配上某一个异常信息那么执行对应catch中的异常处理逻辑, 逻辑执行完毕,整个try…catch运行完毕,代码继续向下运行;
    3. 如果try中的异常与所有catch异常都不匹配,那么JVM自动处理异常
  3. 注意:

    1. 多个catch中只会执行到其中一个符合异常的匹配 ;

    2. 如果有多catch语句去捕获多个异常,那么一定要将子类的异常写在上面的catch中,将父类异常写在下面的catch中(因为父类异常能使用多态获取子类异常,那下面catch中的代码就没有执行到的机会,于是系统报出错误)。

  4. 运行:

    public class MoreCatchDemo {
    
    	public static void main(String[] args) {
    		int[] arr = {1, 5};
    		try {
    			//可能会出现异常的代码
    			getArrIndex(arr, 4);
    		}
    		catch(NullPointerException e) {
    			System.out.println("数组不能为空");
    		}
    		catch(ArrayIndexOutOfBoundsException e) {
    			System.out.println("超过数组的长度");
    		}
    	}
    
    	public static void getArrIndex(int[] arr, int i) {
    		System.out.println(arr[i]);
    		
    	}
    
    }
    

自定义异常

项目需求总有些场景需要异常信息但是JDK没有给提供, 数字范围的问题定义步骤:

  1. 创建出一个类, 让这个类的名字以Exception为结尾, 以Exception为结尾就是一个类型标志, 表示这个类是一个异常类

  2. 这个类必须作为Exception或者是RuntimeException的子类

    1. 如果是Exception的子类,那么这个异常类型就是编译异常(一旦出现必须声明或者处理)

    2. 如果是RuntimeException的子类,那么这个异常类型就是运行时异常(出现后不需要做任何处理)

  3. 可以写有些构造方法, 一般情况下异常中都可以通过构造输入字符串具体异常信息

代码:

public class MyException extends RuntimeException{//继承Exception需要在方法名后throws声明异常
	//继承RuntimeException可以声明也可以不声明,不需要在方法名后声明
	MyException(){}
	
	MyException(String message){
	super(message);
	}
}

/*
 * 测试自定义异常
 * */
public class MyExceptionTest {

	public static void main(String[] args) throws MyException {
		int age = 11;
		if(age < 0) {
			throw new MyException("年龄不能为负数");
		}
	}
}

异常信息打印

异常信息的打印通常使用于 catch代码块中, 用于将异常的详细信息进行输出, 便于开发人员进行问题的排查

  1. getMessage() : 最简洁的异常信息打印

  2. toString() : 相对比较简洁的异常信息, 包括异常的类型, 简短的异常原因

  3. printStackTrace() : 将异常的最详细的信息进行输出, 没有返回值类型,只有第三种是开发中比较常用的

try{

方法应用----> 牵连处很多逻辑处理----> 就会有很多的异常

}catch(Exception ex){

ex.printStackTrace(); // 为了让开发人员进行错误排查,输出的信息打印到日志中,就是代码的运行过程记载文件

}

递归

递归 : 递,表示传递,一个接着一个 ; 归 : 回归, 回归到本质

递归 : 在Java中就是表示方法的调用方式, 方法自己调用自己

递归的使用场景 : 1) 规律性很强 2) 功能的实现过程,都是方法本身的运行过程,只不过运行过程需要反复 3) 要求递归一定是随着方法的运行,数据范围越来越小

例子:

​ 求一个数字的阶乘

​ 5 ! = 5 * 4 * 3 * 2 * 1

​ 4 ! = 4 * 3 * 2 * 1

代码:

package com.zgjy.digui;
public class JieChengDemo {
	public static void main(String[] args) {
		int total = jieCheng(5);
		System.out.println(total);// 120
		
		System.out.println(jieChengDiGui(5));// 120
	}
	
	// 1. 没有使用递归
	public static int jieCheng(int n) {
		// 阶乘从n乘到1结束
		int total = 1;
		// 1. 需要将n到1的每一个数字获取到
		for(int i = n ; i >= 1 ; i--) {
			total = total * i ;
		}
		return total;
	}
	/*
	 *  5 ! = 5 * 4 * 3 * 2 * 1 ---> 5 * 4!--->5表示参数n----> n * (n-1)!
        4 ! = 4 * 3 * 2 * 1---> 4 * 3!--->4表示n---> n*(n-1)!
                一次类推,到n = 1 , 结束
	 * 
	 * 
	 *  参数n为3: 表示求3!
	 *  1. return n*jieChengDiGui(n-1)  ---->  3 * jieChengDiGui(2) ; 3 * 2 = 6
	 *  2. jieChengDiGui(2)---> 2 * jieChengDiGui(2-1)---->2 * jieChengDiGui(1) ; 2 * 1 = 2
	 *  3. jieChengDiGui(1)---> return 1;
	 * 
	 * */
	public static int jieChengDiGui(int n) {
		/*if( n == 1 ) {
			return 1;
		}*/
		return n * jieChengDiGui(n-1); // n * (n-1)!
	}
}

内存图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cTdzUXh3-1575467332907)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20191204213848691.png)]

结论:

​ (1)使用递归运行方式,性能不好,因为同时有多个方法在栈内存中,内存的利用很低。

engDiGui(2) ; 3 * 2 = 6
* 2. jieChengDiGui(2)—> 2 * jieChengDiGui(2-1)---->2 * jieChengDiGui(1) ; 2 * 1 = 2
* 3. jieChengDiGui(1)—> return 1;
*
* */
public static int jieChengDiGui(int n) {
/if( n == 1 ) {
return 1;
}
/
return n * jieChengDiGui(n-1); // n * (n-1)!
}
}


内存图:

[外链图片转存中...(img-cTdzUXh3-1575467332907)]

结论:

​	(1)使用递归运行方式,性能不好,因为同时有多个方法在栈内存中,内存的利用很低。

​	(2)如果写了递归,一定要给递归一个出口,出口就是return一个具体结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值