我们在写代码的时候,经常会遇到错误,并且编译器会给出相关提示 如:
这里就会显示 ArrayIndexOutOfBoundsException
*(数组越界)*错误。并且会提示报错的行号。
同时我们发现 ArrayIndexOutOfBoundsException
是可以点击进去的,点击进去之后会发现是一个JDK自带的类
由此我们可以知道:
在Java中,不同类型的异常,都有与其对应的类来进行描述,也可以说异常也是一种类
但是我们在日常编写项目时,错误是时常发生的。我们作为程序员当然不希望一个项目时不时的崩溃。
在此之前,我们通常对代码可能出现的潜在问题用 条件判断来进行处理:,下面我以一个简略的游戏进行演示:
可以看到当条件一旦增加,代码就会非常臃肿,并且难以后续对功能进行增加和修改。
所以我们必须要学会如何使用,以及处理异常的方式!!
在编写程序时,如果程序中出现错误,此时就需要将错误的信息告知给调用者
关键字:
throw
语法:throw new 异常类型(要告知的信息);
代码案例:
public static void func(int[] arrays) {
//如果传递的是一个空数组,抛出异常
if(arrays == null) {
//这里的NullPointerException是Java自带的一个类
throw new NullPointerException("你传递了一个空指针");
}
}
public static void main(String[] args) {
int[] arrays = null;
func(arrays);
}
运行结果:
注意事项
我们可以看到,在IDEA中,如果异常后还有代码,会直接提示编译错误(因为无法被执行!)
关键字:
throws
语法格式: 修饰符 返回值类型 方法名(参数列表) throws 异常类型1,异常类型2…{ }
如果我们在使用方法是,有编译时异常(编译器警告),可以使用throws来声明这个异常可能会存在,这样就可以通过编译时异常了。
下面我以clone方法为例子:如果不对main函数进行异常声明,会提示clone编译错误(无法确定能否被克隆)
我们在main函数(使用者)后加入声明:throws CloneNotSupportedException
发现编译错误消失,可以正常运行:
class Student implements Cloneable{
public String name;
public int age;
//构造方法:
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
Student s1 = new Student("张三",18);
Student s2 = (Student) s1.clone();
}
}
注意事项
关键字:
try - catch
语法格式: try{ // 将可能出现异常的代码放在这里 }catch(要捕获的异常类型 e){ //异常处理内容 }[catch(异常类型 e){ // 对异常进行处理 }finally{ // 此处代码一定会被执行到 }]
解释:
(不推荐用此写法,无法判断异常类型!!)
注意事项:
这里就是因为父类 RuntimeException在前,后续的InputMismatchException无法被执行,出现编译错误。 子类在前则只会抛出子类的异常,而不会抛出父类的异常。
public static int func3() {
Scanner scanner = new Scanner(System.in);
try{
int a = scanner.nextInt();
return a;
} catch (InputMismatchException e) {
//InputMismatchException是错误输入类型异常
// (这里我想要输入的是int,但是输入String就会报此错误)
e.printStackTrace();
System.out.println("发生了InputMismatchException异常");
}finally {
scanner.close();
System.out.println("Scanner资源已经关闭!!!");
return 100;
}
}
public static void main(String[] args) {
int ret = func3();
System.out.println(ret);
}
注意这里,try语句中已经有了return 语句了, 正常情况下输出的结果是你输入的数;
我们进行输入测试:
我们会发现最终return的值是100,即为finally return的值,
这说明:finally不仅一定会执行,而且可以在return之后最后执行。
既然异常是一个类,那我们肯定也能通过定义类,来定义一个自定义的异常类型。
具体如何定义呢 ?,我们可以仿照已知的异常类,这里是NullPointerException为例子:
其定义方法为:
下面我以一个简单的登录代码来进行演示:
首先是 登录功能类:
public class Login {
//这里是字段:
public String userName;
public String passWord;
//进行简单的逻辑判断
public void login(String userName,String passWord) {
//如果输入的信息不匹配该类的成员信息,抛出自定义异常!(这里只抛出,不解决)
if(!this.userName.equals(userName)) {
throw new UserNameException("账户名输入错误!!!");
}
if(!this.passWord.equals(passWord)) {
throw new PassWordException("密码输入错误!!!");
}
}
//构造函数
public Login(String userName, String passWord) {
this.userName = userName;
this.passWord = passWord;
}
}
自定义类:
首先是用户名错误的异常类:
public class UserNameException extends RuntimeException {
public UserNameException() {
super();
}
public UserNameException(String userName) {
super(userName);
}
}
其次是密码错误类:
public class PassWordException extends RuntimeException{
public PassWordException() {
}
public PassWordException(String message) {
super(message);
}
}
在主函数中实例化:
public class Main {
public static void main(String[] args) {
try {
Login login = new Login("admin","123123");
login.login("admin","123");
}catch (UserNameException e) {
//打印函数栈信息
e.printStackTrace();
}catch (PassWordException e) {
//打印函数栈信息
e.printStackTrace();
}finally {
System.out.println("finally被执行,程序继续...");
}
}
}
输出结果:显示了自定义的异常类型 PassWordException
异常的处理流程: