视频链接:https://www.bilibili.com/video/BV1Rx411876f?p=1
视频范围P629 - P659
目录描述
异常
1.异常概述
- 异常:以下程序执行过程中发生了不正常的情况
package exception;
public class ExceptionTest01 {
public static void main(String[] args) {
int a = 10;
int b = 0;
int c = a / b;
System.out.println(c);
}
}
JVM打印的异常信息:
Exception in thread “main” java.lang.ArithmeticException: / by zero
at exception.ExceptionTest01.main(ExceptionTest01.java:7)
- java提供异常处理机制作用:java把异常信息打印输出到控制台,供程序员参考,看到异常信息之后,可以对程序进行修改,让程序更加健壮
- 当上面代码中,JVM执行到int c = a / b;会new异常对象:new ArithmeticException(" / by zero "),并且JVM将new的异常对象抛出,打印输出信息到控制台了
2.异常存在形式
- 异常在java中以类的形式存在,每一个异常类都可以创建异常对象
- 异常对应的现实生活:
类是:模板
对象是:实际存在的个体
比如:
火灾是(异常类);
2022年3月13日,小红家着火了(异常对象)
package exception;
public class ExceptionTest02 {
public static void main(String[] args) {
//通过“异常类”实例化“异常对象”
NumberFormatException nfe = new NumberFormatException("数字格式化!");
System.out.println(nfe);//输出为:java.lang.NumberFormatException: 数字格式化!
NullPointerException npe = new NullPointerException("空指针异常发生了!");
System.out.println(npe);//输出为:java.lang.NullPointerException: 空指针异常发生了!
}
}
3.异常的继承结构
3.1 UML图
- UML是一种统一建模语言,一种图标式语言(画图的)
- UML不是只有java中使用,只要是面向对象的编程语言都有UML
- 画UML图的都是:软件架构师或者系统分析师,或者软件设计人员
- UML图中可以描述类和类之间的关系,程序执行的流程,对象的状态
- 画UML图的工具:Rational Rose(收费)、starUML(免费)…
3.2 异常的继承结构图
- Object
- Object下有Throwable(可抛出的)
- Throwable下有两个分支:Error(不可处理,直接退出JVM)和Exception(可处理的)
- Exception下有两个分支:
Exception的直接子类:编译时异常(要求程序员在编写程序阶段必须预先对这些异常进行处理,如果不处理,编译器报错)
RuntimeException:运行时异常(在编写程序阶段程序员可以预先处理,也可以不管)
使用starUML绘制:
3.3 编译时异常 和 运行时异常 区别
- 这两个异常多是发生在运行阶段,编译阶段这两个异常是不会发生的
- 编译时异常命名由来:因为编译时异常必须在编译(编写)阶段预先处理,如果不处理编译器报错
- 所有异常都是在运行阶段发生的,因为只有程序运行阶段才可以new对象(异常的发生就是new异常对象)
- 编译时异常又被称为受检异常(CheckedException)、受控异常
- 运行时异常又被称为未受检异常(UnCheckedException)、非受控异常
-
编译时异常一般发生的概率比较高
举例:你看见外面下雨,倾盆大雨,你出门之前会预料到:如果不打伞,我可能会生病(生病是一种异常)。而且这个异常发生的概率很高,所以我们出门之前要拿一把伞。
“拿把伞”就是对“生病异常”发生之前的一种处理方式
对一些发生概率较高的异常,需要在运行之前对其进行预处理 -
运行时异常一般发生的概率比较低
举例:小明走在大街上,可能会被天上的飞机轮子砸到(被砸到也是一种异常)。但是这种异常发生概率较低。
在出门之前没必要提前对这种发生概率较低的异常进行预处理,如果进行预处理,就会很累。 -
如果java没有对异常进行划分,没有分为:编译时异常 和 运行时异常
那么所有的异常都需要在编写程序阶段对其进行预处理,虽然程序这样肯定是绝对的安全,但是程序员编写程序太累,代码到处都是处理异常的代码。
4.异常的处理方式
- 第一种方式:在方法声明的位置上,使用throws关键字,抛给上一级
- 第二种方式:使用try…catch语句进行异常的捕捉
举例:
我是某集团的一个销售员,因为我的失误,导致公司损失了1000元,“损失1000元”这可以看做是一个异常发生了,我有两种处理方式:
第一种方式:我把这件事情告诉了我的领导【异常上抛】
第二种方式:我自己掏腰包把这个钱补上【异常的捕捉】
- 异常发生之后,如果我选择了上抛,抛给了我的调用者,调用者需要对这个异常继续处理,那么调用者处理这个异常同样有两种处理方式
- java中异常发生之后如果一直上抛,最终抛给了main方法,main方法继续向上抛,抛给了调用者JVM,JVM知道这个异常发生,只有一个结果,终止java程序的执行
- 只要异常没有捕捉,采用上报的方式,此方法的后续代码不会执行
- try语句块中的某一行出现异常,该行后面的代码不会执行,try…catch捕捉异常之后,后续代码可以执行
- 如果希望调用者来处理,选择throws上报
4.1 运行时异常举例
ArithmeticException 继承 RuntimeException,属于运行时异常,在编写程序阶段不需要对这种异常进行预先的处理
package exception;
public class ExceptionTest03 {
public static void main(String[] args) {
/*程序执行到此处发生了ArithmeticException异常,
底层new了一个ArithmeticException异常对象,
然后抛出了,由于是main方法调用了100 / 0,
所以这个异常ArithmeticException抛给了main方法,
main方法没有处理,将这个异常自动抛给了JVM,
JVM最终终止程序的执行。
*/
System.out.println(100 / 0);
//这里没有输出,没有执行
System.out.println("hello world!");
}
}
4.2 编译时异常举例
以下代码报错的原因:
因为doSome()方法声明位置上使用了:throws ClassNotFoundException,而ClassNotFoundException是编写代码时异常,没有处理,编译器就报错
package exception;
public class ExceptionTest04 {
public static void main(String[] args) {
//main方法中调用doSome()方法
//因为doSome()方法声明位置上有:throws ClassNotFoundException
//我们在调用doSome()方法的时候必须对这种异常进行预先的处理
//如果不处理,编译器就报错
//编译器报错信息:Unhandled exception: java.lang.ClassNotFoundException
doSome();
}
/**
* doSome()方法在方法声明的位置上使用了:throws ClassNotFoundException
* 这个代码表示doSome()方法在执行过程中,有可能会出现ClassNotFoundException异常
* 叫做类没找到异常,这个异常直接父类是:Exception 所以ClassNotFoundException属于编译时异常
* @throws ClassNotFoundException
*/
public static void doSome() throws ClassNotFoundException{
System.out.println("doSome!!!");
}
}
解决方案
第一种方式:
在方法声明的位置上继续使用:throws 来完成异常的继续上抛,抛给调用者
上抛类似于推卸责任(继续把异常传递给调用者)
package exception;
public class ExceptionTest05 {
public static void main(String[] args) throws ClassNotFoundException {
doSome();
}
public static void doSome() throws ClassNotFoundException{
System.out.println("doSome!!!");
}
}
第二种方式:
try…catch进行捕捉
捕捉等于把异常拦下了,异常真正的解决了(调用者是不知道的)
package exception;
public class ExceptionTest05 {
public static void main(String[] args) {
try {
doSome();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void doSome() throws ClassNotFoundException{
System.out.println("doSome!!!");
}
}
4.3 处理异常的第一种方式:throws
在方法声明的位置上使用throws关键字抛出,谁调用这个方法,就抛给谁,抛给调用者来处理
处理异常的态度:上报
package exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ExceptionTest06 {
public static void main(String[] args) throws FileNotFoundException {
System.out.println("main begin");
m1();
System.out.println("main over");
}
private static void m1() throws FileNotFoundException {
System.out.println("m1 begin");
m2();
System.out.println("m1 over");
}
//private static void m2() throw ClassCastException{ //抛别的不行,抛ClassCastException说明还是没有对FileNotFoundException处理
//private static void m2() throws IOException { //抛出FileNotFoundException的父对象IOException是可以的,IOException包括FileNotFoundException
//private static void m2() throws Exception { //可以,Exception包括所有的异常
//private static void m2() throws ClassCastException,FileNotFoundException {//throws后面也可以写多个异常,可以使用逗号隔开
private static void m2() throws FileNotFoundException {
System.out.println("m2 begin");
//编译器报错:m3()方法声明位置上有:throws FileNotFoundException
//这里调用m3()方法没有对异常进行预处理,所以编译报错
//m3();
m3();
System.out.println("m2 over");
}
private static void m3() throws FileNotFoundException {
//调用SUN jdk中某个类的构造方法,后期IO流会讲
//功能:创建一个输入流对象,该流指向一个文件
/*报错原因:
* 第一:这里调用了一个构造方法:FileInputStream(String name)
* 第二:这个构造方法的声明位置上有:throws FileNotFoundException
* 第三:通过类的继承结果看到:FileNotFoundException父类是IOException,IOException的父类是Exception
* 最终得知:FileNotFoundException是编译时异常
*
* 错误原因:编译时异常要求程序员编写程序阶段必须对它进行处理,不处理编译器就报错
* */
//new FileInputStream("C:\\Users\\keith\\1.txt");
new FileInputStream("C:\\Users\\keith\\1.txt");
}
}
总结:一般不建议在main方法上使用throws,因为这个异常如果真正的发生了,一定会抛给JVM,JVM只有终止,异常处理机制的作用就是增强程序的健壮性,所以一般main方法中的异常建议使用try…catch进行捕捉,main就不要继续上抛了。
4.4 处理异常的第二种方式:try…catch
使用try…catch语句对异常进行捕捉
这个异常不会上报(上抛),自己把这个事儿处理了
package exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ExceptionTest06 {
public static void main(String[] args) {
System.out.println("main begin");
try {
//try 尝试
m1();
} catch (FileNotFoundException e) {//catch后面的好像一个方法的形参
//这个分支中可以使用e引用,e引用保存的内存地址是那个new出来异常对象的内存地址
//catch是捕捉异常之后走的分支
System.out.println("文件不存在,可能路径错误,也可能该文件被删除了!");
}
//try..catch把异常抓住之后,这里代码会继续执行
System.out.println("main over");
}
private static void m1() throws FileNotFoundException {
System.out.println("m1 begin");
m2();
System.out.println("m1 over");
}
private static void m2() throws FileNotFoundException {
System.out.println("m2 begin");
m3();
System.out.println("m2 over");
}
private static void m3() throws FileNotFoundException {
new FileInputStream("C:\\Users\\keith\\1.txt");
}
}
当路径正确的时候,运行结果:
当路径不正确的时候,运行结果:
4.5 深入 try…catch
- catch后面的小括号中的类型可以是具体的异常类型,也可以是异常类型的父类型
- catch可以写多个,建议catch的时候,精确的一个一个处理,这样有利于程序的调试
- catch写多个的时候,从上到下,必须遵守从小到大
测试实验一:
package exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ExceptionTest07 {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("C:\\Users\\keith\\1.txt");
System.out.println("以上出现异常,这里无法执行!!!");
} catch (FileNotFoundException e) {
System.out.println("文件不存在!");
}
System.out.println("hello world!!!");
}
}
当路径正确的时候,运行结果:
当路径不正确的时候,运行结果:
测试实验二:
package exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ExceptionTest07 {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("C:\\Users\\keith\\12.txt");
} catch (IOException e) {//多态:IOException e = new FileNotFoundException();
System.out.println("文件不存在!");
}
System.out.println("hello world!!!");
}
}
package exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ExceptionTest07 {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("C:\\Users\\keith\\12.txt");
} catch (Exception e) {//多态:Exception e = new FileNotFoundException();
System.out.println("文件不存在!");
}
System.out.println("hello world!!!");
}
}
测试实验三:
package exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ExceptionTest07 {
public static void main(String[] args) {
try {
//创建输入流
FileInputStream fis = new FileInputStream("C:\\Users\\keith\\12.txt");
//读文件
fis.read();
} catch (FileNotFoundException e) {//多态:IOException e = new FileNotFoundException();
System.out.println("文件不存在!");
}catch (IOException e){
System.out.println("读取失败!");
}
System.out.println("hello world!!!");
}
}
测试实验四:
JDK8的新特性
package exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ExceptionTest07 {
public static void main(String[] args) {
try {
//创建输入流
FileInputStream fis = new FileInputStream("C:\\Users\\keith\\12.txt");
System.out.println(100 / 0);//这个异常是运行时异常,编写程序的时候可以处理,也可以不处理
} catch (FileNotFoundException | ArithmeticException | NullPointerException e) {
System.out.println("文件不存在?数学异常?空指针异常?");
}
}
}
5.异常对象的常用方法
5.1 getMessage方法
获取异常简单的描述信息
String msg = exception.getMessage();
演示代码:
package exception;
public class ExceptionTest08 {
public static void main(String[] args) {
//这里只是new了异常对象,但是没有将异常对象抛出,JVM会认为这是一个普通的java对象
NullPointerException e = new NullPointerException("空指针异常!!!");
//获取异常简单描述信息:这个信息实际上就是构造方法上面String参数
String msg = e.getMessage();
System.out.println(msg);//输出为:空指针异常!!!
}
}
5.2 printStackTrace()方法
打印异常追踪的堆栈信息:
exception.printStackTrace();
演示代码一:
package exception;
public class ExceptionTest08 {
public static void main(String[] args) {
//这里只是new了异常对象,但是没有将异常对象抛出,JVM会认为这是一个普通的java对象
NullPointerException e = new NullPointerException("空指针异常!!!");
//打印异常堆栈信息
//java后台打印异常堆栈追踪信息的时候,采用了异步线程的方式打印的
e.printStackTrace();
System.out.println("hello world!!!");
}
}
运行结果:
演示代码二:
package exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ExceptionTest09 {
public static void main(String[] args) {
try {
m1();
} catch (FileNotFoundException e) {
//打印异常堆栈追踪信息
//在实际开发中,建议使用这个,养成好习惯
e.printStackTrace();
}
//这里程序不耽误执行,很健壮【服务器不会因为遇到异常而宕机/死机】
System.out.println("hello world!");
}
private static void m1() throws FileNotFoundException {
m2();
}
private static void m2() throws FileNotFoundException {
m3();
}
private static void m3() throws FileNotFoundException {
new FileInputStream("C:\\Users\\keith\\12.txt");
}
}
运行结果:
6.查看异常的追踪信息
- 从上往下一行一行看
- SUN写的代码就不用看了,主要的问题出现在自己编写的代码上【看包名判断是不是SUN写的】
演示:
注:第一行是异常信息,中间的是SUN写的,下面的是自己的错误部分!
7.finally关键字
- finally子句属于try…catch语句中
- 在finally子句中的代码时最后执行的,并且是一定会执行的,即使try语句块中的代码出现了异常。
- finally子句必须和try一起使用,不能单独编写
- 通常在finally语句块中完成资源的释放/关闭,因为finally中的代码比较有保障,即使try语句块中的代码出现异常,finally中代码也会正常执行
7.1 代码实训一
package exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ExceptionTest10 {
public static void main(String[] args) {
//声明位置放在try外面,这样在finally中才能用
FileInputStream fis = null;
try {
//创建输入流对象
fis = new FileInputStream("C:\\Users\\keith\\12.txt");
//开始读文件...
String s = null;
//这里一定会出现空指针异常!
s.toString();
//流使用完需要关闭,因为流时占用资源的
//即使以上程序出现异常,流也必须要关闭!
//放在这里有可能流关不了
//fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}catch (NullPointerException e){
e.printStackTrace();
}finally {
//流的关闭放在这里比较保险
//finally中的代码是一定会执行的
//即使try中出现了异常
if (fis != null) {//避免空指针异常
try {
fis.close();//close()方法有异常,采用捕捉的方式
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
7.2 代码实训二
- try和finally,没有catch也是可以使用的,即try和finally可以联合使用
- try不能单独使用
- 放在finally语句块中的代码是一定会执行的
以下代码执行顺序:
- 先执行try
- 再执行finally
- 最后执行return(return语句只要执行,方法必然结束)
package exception;
public class ExceptionTest11 {
public static void main(String[] args) {
try {
System.out.println("try");
return;
}finally {
System.out.println("finally");
}
//这里不能写语句,因为这个代码是无法执行到的
//System.out.println("hello");
}
}
运行结果:
7.3 代码实训三
退出JVM之后,finally语句中的代码就不执行了
package exception;
public class ExceptionTest12 {
public static void main(String[] args) {
try {
System.out.println("try");
//退出JVM
System.exit(0);
}finally {
System.out.println("finally");
}
}
}
7.4 finally面试题
package exception;
public class ExceptionTest13 {
public static void main(String[] args) {
int result = m();
System.out.println(result);//输出为:100
}
/*
java语法规则:
1.方法体中的代码必须遵循自上而下顺序依次逐行执行
2.return语句一旦执行,整个方法必须结束
*/
private static int m() {
int i = 100;
try{
//这行代码出现在int i = 100;下面,所以最终结果必须是返回100
//return语句还必须保证是最后执行的,一旦执行,整个方法结束
return i;
}finally {
i++;
}
}
}
m()函数反编译之后效果:
private static int m() {
int i = 100;
int j = i;
i++;
return i;
}
8.final、finalize和finally区别
final | 关键字 | final修饰的类无法继承;final修饰的方法无法覆盖;final修饰的变量不能重新赋值 |
finally | 关键字 | 和try一起联合使用;finally语句块中的代码时必须执行的 |
finalize | 标识符 | 是一个Object类中的方法名,整个方法是由垃圾回收器GC负责调用 |
package exception;
public class ExceptionTest14 {
public static void main(String[] args) {
//final是一个关键字,表示最终的,不变的
final int i = 100;
//i = 200;
//finally也是一个关键字,和try联合使用,使用在异常处理机制中
//在finally语句块中的代码是一定会执行的
try{
}finally {
System.out.println("finally");
}
//finalize()是Object类中的一个方法,作为方法名出现
//所以finalize是标识符
//finalize()方法是JVM的GC垃圾回收器负责调用
Object obj;
}
}
9.如何自定义异常类
SUN提供的JDK内置的异常肯定是不够用的,在实际的开发中,有很多业务,这些业务出现异常之后,JDK中都是没有的, 和业务挂钩的,那么异常类可以由程序员自己定义。
Java中自定义异常两步骤:
- 编写一个类继承Exception或者RuntimeException
- 提供两个构造方法,一个无参数的,一个带有String参数的
异常类:
package exception;
public class MyException extends Exception {//编译时异常
public MyException(){
}
public MyException(String s){
super(s);
}
}
/*
public class MyException extends RuntimeException {//运行时异常
}*/
测试类:
package exception;
public class ExceptionTest15 {
public static void main(String[] args) {
//创建异常对(只new了异常对象,并没有手动抛出)
MyException e = new MyException("用户名不能为空!");
//打印异常堆栈信息
e.printStackTrace();
//获取异常简单描述信息
String msg = e.getMessage();
System.out.println(msg);
}
}
运行结果:
10.异常在实际开发中的作用
异常类:
栈操作异常
package exception;
public class MyStackOperationException extends Exception {
public MyStackOperationException() {
}
public MyStackOperationException(String message) {
super(message);
}
}
栈:
package exception;
public class MyStack {
//向栈中存储元素,这里使用一维数组模拟,存到栈中,就表示存储到数组中
//Object类型数组可以存储java中的任何引用类型的数据(一般对象的超级父类就是Object)
//String父类也是Object,但是在java中有优待,不需要new也是一个对象
//private Object[] elements = new Object[10]; 也可以这样进行初始化 //等号在构造方法执行的时候赋值
private Object[] elements;
//栈帧 永远指向栈顶元素
private int index = -1;
//无参构造方法
public MyStack() {
//默认初始化栈容量10
this.elements = new Object[10];
}
//压栈
public void push(Object obj) throws MyStackOperationException {
if (this.index >= this.elements.length - 1){
/*System.out.println("压栈失败,栈已满!");
return;*/
//创建异常对象
MyStackOperationException e = new MyStackOperationException("压栈失败,栈已满!");
//手动将异常抛出去
//这里捕捉没有意义,自己new一个异常,自己捉没有意义。栈已满这个信息需要传递出去
throw e;
//合并上面的 手动抛出异常
//throw new MyStackOperationException("压栈失败,栈已满!");
}
//程序能够走到这里,说明栈没满
//向栈中加1个元素,栈帧向上移动一个位置
this.index++;
this.elements[index] = obj;
//上面两行可以等价于
//this.elements[++index] = obj;
//obj是一个引用,自动调用引用的toString()方法 如:obj.toString()
System.out.println("压栈"+ obj + "元素成功,栈帧指向 " + this.index);
}
//弹栈
public void pop() throws MyStackOperationException {
if (this.index < 0){
/*System.out.println("栈已空,弹栈失败!");
return;*/
throw new MyStackOperationException("栈已空,弹栈失败!");
}
//程序能够走到这里,说明栈没空
System.out.println("弹栈"+ this.elements[this.index] + "元素成功 ");
//栈帧向下移动一位
this.index--;
System.out.println(" 栈帧指向 " + this.index);
}
//set和get方法也许用不上,但是必须写,这是规矩
//封装:第一步:属性私有化 第二步:对外提供set和get方法
public Object[] getElements() {
return elements;
}
public void setElements(Object[] elements) {
this.elements = elements;
}
}
自定义测试类:
package exception;
//测试改良后的MyStack
public class ExceptionTest16 {
public static void main(String[] args) {
//创建栈对象
MyStack stack = new MyStack();
//压栈
try {
stack.push(new Object());
stack.push(new Object());
stack.push(new Object());
stack.push(new Object());
stack.push(new Object());
stack.push(new Object());
stack.push(new Object());
stack.push(new Object());
stack.push(new Object());
stack.push(new Object());
//这里栈满了
stack.push(new Object());
} catch (MyStackOperationException e) {
//输出异常的简单信息
System.out.println(e.getMessage());
}
//弹栈
try {
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
//弹栈失败
stack.pop();
} catch (MyStackOperationException e) {
System.out.println(e.getMessage());
}
}
}
运行结果:
11.异常和方法覆盖
在方法覆盖内容部分,有一个遗留问题:
重写之后的方法不能比重写之前的方法抛出更多(更宽泛)的异常,可以更少
package exception;
class Animal{
public void doSome(){
}
public void doOther() throws Exception{
}
}
class Cat extends Animal{
//错误
/*public void doSome() throws Exception{
}*/
//编译正常
public void doSome() throws RuntimeException{
}
//编译正常
/* public void doOther(){
}*/
/*//编译正常
public void doOther() throws Exception{
}*/
//编译正常
public void doOther() throws NullPointerException{
}
}
总结异常中的关键字:
异常捕捉:try、catch、finally
throws:在方法声明位置上使用,表示上报异常信息给调用者
throw:手动抛出异常!
12.异常作业
编写程序模拟用户注册:
- 程序开始执行时,提示用户输入“用户名”和“密码”信息
- 输入信息之后,后台java程序模拟用户注册
- 注册时用户名要求长度在[6-14]之间,小于或者大于都表示异常
注意:完成注册的方法放到一个单独的类中,异常类自定义即可。
class UserService{
public void register(String username,String password){
//这个方法中完成注册!
}
}
编写main方法,在main方法中接收用户输入的信息,在main方法中调用UserServicv的register方法完成注册!
自定义异常类:
package exception.homework;
public class IllegalNameException extends Exception{
public IllegalNameException() {
}
public IllegalNameException(String message) {
super(message);
}
}
用户业务类:
处理用户相关的业务:例如登录、注册等功能。
package exception.homework;
public class UserService {
/**
* 用户注册
* @param username 用户名
* @param password 密码
* @throws IllegalNameException 当用户名为Null,或者用户名长度小于6,大于14,会出现该异常
*/
public void register(String username,String password) throws IllegalNameException {
/*//引用等于null的这个判断最好放到所有条件的最前面
if (username == null || username.length() < 6 || username.length() > 14){
}*/
//username == null 不如写成: null == username 避免手误写成:username = null 将空值赋给变量
if (null == username || username.length() < 6 || username.length() > 14){
throw new IllegalNameException("用户名不合法,长度必须在[6-14]之间!");
}
//程序执行到此处说明用户名合法
System.out.println("注册成功,欢迎[" + username + "]");
}
}
测试类:
package exception.homework;
public class Test {
public static void main(String[] args) {
//创建UserService对象
UserService userService = new UserService();
//用户名和密码就不再从控制台接收了
try {
userService.register("zhangsan","123");
} catch (IllegalNameException e) {
System.out.println(e.getMessage());
}
}
}
运行结果: