【从零开始的Java秃头之旅】03

从零开始的Java秃头之旅之Java篇

这几天主要学习了Java当中的异常这一概念,直接看图
【从零开始的Java秃头之旅】03_第1张图片java.lang.Throwable类是java语言中所有错误或异常的超类(父类),其主要可以分为两类:

Exception:编译期异常,继续编译java程序出现的问题(其中又分为了运行期异常(RuntimeException)以及非运行时异常(IOException)。
Error:错误,错误就相当于程序得了一个无法治愈的毛病,必须修改源代码,程序才能继续执行。

那接下来说一下怎样处理异常:

处理异常一共有两种方式:

1.throws关键字:(交给别人处理)
解释:当方法内部抛出异常对象的时候,我们就必须处理这个异常对象
可以使用throws关键字处理异常对象,会把异常对象声明抛出给方法的调用者处理(自己不处理,给别人处理),最终交给JVM处理(也就是中断处理)

使用格式:在方法声明时使用

修饰符 返回值类型 方法名(参数列表) 
			throws AAAException,BBBExcetpion ...{
 					throw new AAAException("产生原因");
 					throw new BBBException("产生原因");
 					...
 	}

下面有几个注意事项:

  1. throws关键字必须写在方法声明处
  2. throws关键字后边声明的异常必须是Exception或者是Exception的子类
  3. 方法内部如果抛出了多个异常对象,那么throws后边必须也声明多个异常,如果抛出的多个异常对象有子父类关系,那么直接声明父类异常即可。
  4. 调用了一个声明抛出异常的方法,我们就必须得处理声明的异常,要么继续使用throws声明抛出,把异常交给方法的调用者处理,最终交给JVM中断处理

2.try…catch方法
格式:

			try{
					//可能产生异常的代码
			}catch(定义一个异常的变量,用来接收try中抛出的异常对象){
				//异常的处理逻辑,异常异常对象之后,怎么处理异常对象
				 	一般在工作中,会把异常的信息记录到一个日志中
			}
			...
			catch(异常类名 变量名){
			
			}

注意:

  1. try中可能会抛出多个异常对象,那么就可以使用多个catch来处理这些异常对象。
  2. 如果try中产生了异常,那么就会执行catch中的异常处理逻辑,执行完毕catch中的处理逻辑,继续执行try…catch之后的代码。
  3. 如果try中没有产生异常,那么就不会执行catch中异常的处理逻辑,执行完try中的代码,继续执行try…catch之后的代码
那么如果我想执行一些无论是否出现异常都要执行的语句,我们要使用哪个关键字呢?

这里就要说到finally关键字

 		try{
 					//可能产生异常的代码
 				}catch(定义一个异常的变量,用来接收try中抛出的异常对象){
 					//异常的处理逻辑,异常异常对象之后,怎么处理异常对象
 					 	一般在工作中,会把异常的信息记录到一个日志中
 				}
 				...
 				catch(异常类名 变量名){
 				
 				}finally{
 					//无论是否出现异常都会执行
 				}

注意:

  1. finally不能单独使用,必须和try一起使用。
  2. finally一般用于资源释放(资源回收),无论程序是否出现异常,最后都要资源释放(IO)。

刚才我们都在都介绍单独一个异常的处理方式,其实多个异常的处理方式也不尽相同,我们这里都用try…catch语句来展示。

多个异常使用捕获的处理方式:

  1. 多个异常分别处理。
			try {
			int arr[] = {1,2,3};
			System.out.println(arr[3]); //ArrayIndexOutOfBoundsException	越界异常
		} catch (ArrayIndexOutOfBoundsException e) {
			System.out.println(e);
		}

			try {
			List list = List.of(1, 2, 3);
			System.out.println(list.get(3)); //ArrayIndexOutOfBoundsException 	
		} catch (ArrayIndexOutOfBoundsException 	 e) {
			System.out.println(e);
		}
		System.out.println("后续代码");
}

这里我们可以看到,list集合和arr[]数组都出现了(索引值)越界异常,我们这里多个异常分别使用try…catch语句分别处理,是否感觉有些繁琐?

  1. 多个异常一次捕获,多次处理。
    这里我们要注意:
    catch里边定义的异常变量,如果有子父类关系,那么子类的异常变量必须写在上边,否则就会报错。
			try {
			int[] arr = {1,2,3};
			System.out.println(arr[3]);     //exception ArrayIndexOutOfBoundsException	越界异常
			List list = List.of(1, 2, 3);
			System.out.println(list.get(3));   //exception ArrayIndexOutOfBoundsException 	
		} catch (ArrayIndexOutOfBoundsException e) {
			System.out.println(e);
		} catch (IndexOutOfBoundsException e) {
			System.out.println(e);
		}

这里我们可以看到,try语句里我们将两个越界异常同时捕获了,但是使用两个catch语句来多次处理,值得注意的是 ArrayIndexOutOfBoundsException
IndexOutOfBoundsException 的子类,根据刚才注意事项,我们知晓应该将子类写在上面。

  1. 多个异常一次捕获一次处理。
		try {
			int[] arr = {1,2,3};
			System.out.println(arr[3]);     //exception ArrayIndexOutOfBoundsException	越界异常
			List list = List.of(1, 2, 3);
			System.out.println(list.get(3));   //exception ArrayIndexOutOfBoundsException 	
		} catch (Exception e) {
			System.out.println(e);
		}
         	System.out.println("后续代码");

那么这边多个异常的多种处理方式也整理完了。最后提醒一点,例如运行时异常被抛出可以不处理。即不捕获也不声明抛出,默认给虚拟机处理,终止程序,什么时候不抛出运行时异常了,再来继续执行程序。

那么接下来讲讲今天最后的内容,也就是自定义异常类。

那么既然异常类型那么多,为什么还要自定义异常类呢?

答:主要是根据自己的需求,出现异常的时候,做特殊的处理。所以尽管Java已经预定义了许多异常类,但有时还需要定义自己的异常。

那么接下来是自定义类的格式:

 		自定义异常类:
 					java提供的异常类,不够我们使用,需要自己定义一些异常类
 		格式:
 					public class XXXException extends Exception / RuntimeException{
 							添加一个空参数的构造方法
 							添加一个带异常信息的构造方法
 					}

注意:

  1. 自定义异常类一般都是以Exception结尾,说明该类是一个异常类。
  2. 自定义异常类,必须得继承Exception或者RuntimeException。
    继承Exception:那么自定义的异常类就是一个编译器异常,如果方法内部抛出了编译器异常,就必须处理这个异常,要么throws,要么try…catch。
    继承RuntimeException:那么自定义的异常类就是一个运行期异常,无需处理,交给虚拟机处理(中断处理)。

这里我们拟做一个登记注册的流程,输出自己注册的ID,如果数据库里又相同的已经注册过的ID,那么就会报错,没有则提示注册成功。

这边先来看一下我们的RegisterException代码:

//继承运行期异常
public class RegisterException extends RuntimeException{
		//添加一个空参数的构造方法
		public RegisterException() {
			
		}
		//添加一个异常信息的构造方法
		//查看源码发现,所有的异常类都会有一个带异常信息的构造方法,方法内部会调用父类带异常信息的构造方法,让父类处理这个异常信息。
		public RegisterException(String message) {
			super();
		}
}

接下里我们来看主方法,并定义一个方法,用来对用户输入的注册用户名进行判断。

public class Demo01RegisterException {
	//1.使用数组保存已经注册过的用户名
	static String[] userNames = {"张三","李四","王五"};
	
	public static void main(String[] args) throws RegisterException {
			//2.使用Scanner获取用户输入的注册的用户名(前端,页面)
			Scanner sc = new Scanner(System.in);
			System.out.println("请输入您要注册的用户名:");
			String username = sc.next();
			checkUsername(username);
			
		}
		//3.定义一个方法,对用户输入的注册的用户名进行判断
	public static void checkUsername(String username) /*throws RegisterException*/ {
		//遍历存储已经注册过用户名的数组,获取每一个用户名
		for(String name : userNames) {
			//使用获取到的用户名和用户输入的用户名比较
			if(name.equals(username)) {
				//true:用户名已经存在了,抛出RegisterException异常,告知用户“亲,该用户名已经被注册”;
				try {
					throw new RegisterException("亲,该用户名已经被注册");
				} catch (RegisterException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					return;				//结束方法
				}
			}
		}
		System.out.println("恭喜您,注册成功!");
	}
}

这里使用try…catch语句。那么我们知道,由于我们的自定义异常类继承的是RuntimeException,也就是运行期异常,由上面可知运行期异常,我们也可以不处理,直接交给虚拟机处理。

public class Demo02RegisterException {
	//1.使用数组保存已经注册过的用户名
	static String[] userNames = {"张三","李四","王五"};
	
	public static void main(String[] args) throws RegisterException {
			//2.使用Scanner获取用户输入的注册的用户名(前端,页面)
			Scanner sc = new Scanner(System.in);
			System.out.println("请输入您要注册的用户名:");
			String username = sc.next();
			checkUsername(username);
			
		}
		//3.定义一个方法,对用户输入的注册的用户名进行判断
	public static void checkUsername(String username) /*throws RegisterException*/ {
		//遍历存储已经注册过用户名的数组,获取每一个用户名
		for(String name : userNames) {
			//使用获取到的用户名和用户输入的用户名比较
			if(name.equals(username)) {
				//true:用户名已经存在了,抛出RegisterException异常,告知用户“亲,该用户名已经被注册”;
				throw new RegisterException("亲,该用户名已经被注册");		//抛出运行期异常,无需处理,交给JVM处理,中断处理
			}
		}
		System.out.println("恭喜您,注册成功!");
	}
}

如上面的代码所示,我们这里既没有throw抛出异常,也没有try…catch处理。但是代码也不会报错。

最后的疑问:为什么Java要设计这样的一个异常类呢?

答:如果没有异常,那么就必须检查特定错误,并在程序中处理它,这样代码的复用率会降低。有了异常机制,就可以把“描述在正常执行过程中做什么事”的代码和“出了问题怎么办”的代码分离。所以设计异常的好处:能够解放判断返回值的方式,提供一种上抛的处理机制,降低代码的判断复杂度,并能保证捕获这个异常,集中处理,增强代码复用率。

你可能感兴趣的:(【从零开始的Java秃头之旅】03)