目录
1.异常概念和分类
2.异常的抛出
3.异常的捕获
3.1异常声明throws
3.2异常捕获try-catch
3.3finally
3.4.异常的处理流程
4.自定义异常类
1.异常概念和分类
public class Test {
public static void test() {
test();
}
public static void main(String[] args) {
System.out.println(10/0);//ArithmeticException
int[] arr = null;
System.out.println(arr.length);//NullPointerException
test();//StackOverflowError
}
}
定义:程序执行过程中发生的不正常行为称为异常。
分类:Throwable (异常体系的顶层类):Error (错误)、Exception (异常):受查异常/编译时期异常、非运行异常/运行时异常。
2.异常的抛出
定义:使用 throw 关键字,抛出一个指定的异常对象,将错误信息告知给调用者。
格式:throw new XXXException (“异常产生的原因”);
public class Test {
public static void main(String[] args) {
int a = 0;
if (a == 0) {
throw new ArithmeticException("分母不能为零");
}
System.out.println(10/0);//不会执行
}
}
注意:1> throw必须写在方法体内部;
2> 如果抛出的是RunTimeException其子类对象,即运行时异常,可不用处理,交给JVM即可;
3> 如果抛出的是Exception及其子类对象,即编译时异常,就必须由用户处理,否则无法通过编译;
4> 异常一旦抛出,其后的代码就不会执行。
3.异常的捕获
3.1异常声明throws
定义:在方法声明时参数列表后,当方法中抛出编译时异常,而用户自己不想处理该异常,此时就可以将异常抛给方法的调用者来处理。即当前方法不处理异常,提醒方法的调用者处理异常。
注意:1> throws必须跟在方法的参数列表之后;
2> 声明的异常必须是Exception或Exception的子类;
3> RunTimeException及其子类的异常不需要声明,交给JVM即可;
4> 如果方法内部抛出多个异常,throws后需跟多个异常类型,之间用逗号隔开;
5> 如果多个异常具有父子类关系,只声明父类即可。
import java.io.FileNotFoundException;
import java.io.IOException;
class Student implements Cloneable {
@Override
protected Object clone() throws CloneNotSupportedException {//抛出异常
return super.clone();
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Student student = new Student();
student.clone();//不抛出异常此行代码会报错
}
public static void main3(String[] args) throws IOException, FileNotFoundException {
//FileNotFoundException是IOException的子类,
//只用写IOException即可
}
}
3.2异常捕获try-catch
import java.io.FileNotFoundException;
import java.io.IOException;
class Student { //此时不支持克隆
@Override
protected Object clone() throws CloneNotSupportedException {//抛出异常
return super.clone();
}
}
public class Test {
public static void main(String[] args) throws Exception {
Student student = new Student();
try { //将可能出现异常的代码放在这里面
student.clone();
int[] arr = null;
System.out.println(arr.length);//这里也有异常,但不会被捕获,先到先得
System.out.println("abc");//若上面抛出了异常,这行代码不会执行
} catch (CloneNotSupportedException e) { //可能捕获的异常
e.printStackTrace();//打印异常所在的行数
throw new RuntimeException(e); //捕获到异常则执行这里面的代码 --- *
}catch (NullPointerException e) {//若上面已经捕捉到了异常,这里就捕获不了了
e.printStackTrace(); //即无法同时捕捉多个异常
throw new NullPointerException();
}
catch (ArithmeticException | IndexOutOfBoundsException e) {
e.printStackTrace();
System.out.println("Exception"); //不建议这样写,因为此时无法准确判断是什么异常
}
catch (Exception e) { //最后一道保险,防止还有异常没有捕获
throw new Exception();//先捕捉子类异常,再捕捉父类异常
}
System.out.println("abcd");//若*行是处理异常,剩下程序不会执行
//若*行只是声明捕获到了异常,剩下程序会继续执行
}
}
3.3finally
有些特定的代码,不论程序是否正常运行,都需要执行,比如程序中打开的资源在程序结束时需要关闭或回收。此时就需要finally来解决资源清扫的扫尾工作。
import java.util.InputMismatchException;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
try {
int a = scanner.nextInt();
int ret = 10/a;
System.out.println("ret的值是"+ret);
//return 1; //若这里是方法,return后finally仍然会执行
}catch (ArithmeticException e) {
System.out.println("捕获到了ArithmeticException异常");
}catch (InputMismatchException e) {
System.out.println("输入的参数类型有误");
}finally { //一定执行
scanner.close();//关闭Scanner
System.out.println("finally被执行了");
//return 1; //当try和finally中都有return时,取finally中的return
} //不建议在finally中写return
System.out.println("ttr-catch-finally之后的代码");
}
}
3.4.异常的处理流程
在方法的调用过程当中,当被调用的方法没有处理异常,会沿着栈把这个异常抛给它的调用者,当调用者也没有处理时,就会抛给JVM,程序会异常终止。
4.自定义异常类
在没学异常之前,我们的代码是这样的:
class Login {
private String userName = "admin";
private String password = "12345678";
public void loginInfo(String userName,String password) {
if (!this.userName.equals(userName)) {
System.out.println("用户名错误");
return;
}if (!this.password.equals(password)) {
System.out.println("密码错误");
return;
}
System.out.println("登陆成功");
}
}
public class Test {
public static void main(String[] args) {
Login login = new Login();
login.loginInfo("adminabc","12345678");//用户名错误
}
}
学了异常后,我们就可以自定义异常类了:
注意:1> 继承于Exception (编译时异常/受查异常) 或RunTimeException (运行时异常/非受查异常),继承哪个根据业务需求;
2> 最好实现一个带有String类型参数的构造方法,参数含义是出现异常的原因,这样代码更具有可读性,出错时更好定位。
public class UserNameException extends RuntimeException{ //不继承就不是异常
//这是运行时异常,可不处理
public UserNameException(String message) {
super(message);
}
}
public class PasswordException extends Exception{ //不继承就不是异常
//这是编译时异常,必须要处理
public PasswordException(String message) {
super(message);
}
}
class Login {
private String userName = "admin";
private String password = "12345678";
public void loginInfo(String userName,String password) throws PasswordException{ //编译时异常必须处理
if (!this.userName.equals(userName)) {
throw new UserNameException(userName+" 用户名错误");
}if (!this.password.equals(password)) {
throw new PasswordException(password+" 密码错误");
}
System.out.println("登陆成功");
}
}
public class Test1 {
public static void main(String[] args) {
Login login = new Login();
try {
login.loginInfo("adminabc", "12345678");//用户名错误
}catch (PasswordException e) { //编译时异常必须处理
e.printStackTrace();
}
}
}
JavaSE终于结束啦!!!!!!
数据结构我来啦!!!!!