异常处理是JAVA的一种编程概念,用于JAVA程序执行中出现的异常或错误情况。
Throwable 异常体系的顶层,其分为 Exception 和 Error 两个子类。
Error 即错误,是JAVA虚拟机无法处理的严重问题。
Exception 即异常,异常产生后,程序员可以通过代码处理,使程序继续运行。
像这样程序还没运行,在编写代码时就报错,就叫编译时异常,也称为受检查异常。
当然,编写代码时的语法错误,是错误!不是异常!
这些在编译时没问题,在程序执行期间发生的异常,就叫运行时异常,也称作非受检查异常。
System.out.println(10 / 0);
int[] arr = {1, 2, 3};
System.out.println(arr[4]);
int[] arr = null;
System.out.println(arr.length);
如果方法内出现异常,就会沿着调用栈向上传递,如果向上传递过程中都没有合适的方式处理异常,就会交给JVM处理,程序就会异常终止。
为了避免出现程序运行终止,JAVA提供了以下程序媛可以通过代码处理异常的方式。
在编写代码时,发现程序出现异常,可以通过throw将异常的信息抛出告知调用者。
语法格式:
throw new XXXXException ("这里书写你异常的信息及产生原因");
使用例子:
int a = 0;
if(a == 0)
{
throw new ArithmeticException ("a=0是异常");
}
throw抛出运行时异常时是不需要处理的 ,只是告知调用者。
但是如果时编译时异常,我们则需要处理,而最简单的处理方式是通过throws处理
语法格式:(一般放在方法声明的地方)
修饰符 返回值类型 方法名 (参数列表) throws 异常类型1,异常类型2...{
}
使用例子:
同样的代码,但是我们将异常类型改为编译时异常
int a = 0;
if(a == 0){
throw new CloneNotSupportedException ("异常为 a = 0");
}
加上throws CloneNotSupportedException后,错误消失
调用声明抛出异常的方法时,调用者必须对该异常进行处理,或者继续使用 throws 抛出
我们以如下代码举例
public static void main(String[] args) {
test();
}
public static void test() throws CloneNotSupportedException{
int a = 0;
if(a == 0){
throw new CloneNotSupportedException("异常为 a = 0");
}
}
我们将Test问题向上抛出给Main方法处理,但是Main没有继续处理,故报错。
解决方法有两种:
① 对异常报错的方法再使用throws声明一下
throws 对异常并没有真正处理,而是将异常报告给抛出异常方法的调用者,由调用者处理。
如果真正要对异常进行处理,就需要try-catch。
② 使用try-catch捕获并处理该异常
语法格式: try{ //将可能出现异常的代码放在这里 } catch ( 异常类型1 e ){ //如果try中的代码抛出异常了,且try的异常类型与catch括号中的异常类型一致,或者catch括号中的异常是try异常类型的父类,就会被catch捕捉到,运行这个大括号里的代码 //在catch里对异常进行正常处理,处理完成后,就会跳出try-catch结构,继续执行后续代码 } catch ( 异常类型2 e ){ //多重catch保险,总有一个try异常能找到属于自己的catch~ //异常处理ing } finally { //后文会讲 //此处代码一定会被运行到 } // 如果没有抛出异常,或者异常被捕获处理了,这里的代码也会执行
使用例子:
public static void main(String[] args){
try {
int a = 10 / 0;
}catch (ArithmeticException e){
System.out.println("捕获到了异常");
}
System.out.println("后续的代码");
}
try异常类型与catch一致,异常成功捕获,由程序员处理,退出代码为0
try {
int a = 10 / 0;
}catch (NullPointerException e){
System.out.println("捕获到了异常");
}
System.out.println("后续的代码");
}
导致结果:异常捕获失败,也就不会被处理,继续往外抛,直到JVM收到中断程序,退出代码为1
public static void main(String[] args){
try {
int a = 10 / 0; //此处出现异常
System.out.println("66666666"); //之后的代码便不会被执行
}catch (ArithmeticException e){
System.out.println("捕获到了异常");
}
System.out.println("后续的代码");
}
运行结果:
try 中可能会抛出多个不同的异常对象,则必须用多个 catch 来捕获,但是只能抛出一个异常
public static void main(String[] args){
try {
int a = 10 / 0;
}catch (NullPointerException e){
System.out.println("捕获到了异常111");
}catch (ArithmeticException e){
System.out.println("捕获到了异常222");
}
System.out.println("后续的代码");
}
运行结果:
如果异常之间具有父子关系,一定是子类异常在前catch,父类异常在后catch,否则则会报错
public static void main(String[] args){
try {
int a = 10 / 0;
}catch (Exception e){
System.out.println("捕获到了异常111");
}catch (NullPointerException e){
System.out.println("捕获到了异常222");
}
System.out.println("后续的代码");
}
Exception 是所有异常的父类,所以报错
在程序正常或者异常退出时,必须要对资源进行回收,而 finally 中的代码一定会执行的,一般在 finally 中进行一些资源清理的扫尾工作
语法格式: try { // 可能会发生异常的代码 } catch ( 异常类型 e ){ // 对捕获到的异常进行处理 } finally { // 此处的语句无论是否发生异常,都会被执行到 } // 如果没有抛出异常,或者异常被捕获处理了,这里的代码也会执行
public static void main(String[] args) {
try {
int a = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("捕获到了异常");
} finally {
System.out.println("finally代码");
}
System.out.println("后续的代码");
}
运行结果:
假设我们有一个用户登录账号密码的项目业务,处理用户名错误和密码错误的时候可能你会这样写代码
public class Login{
private String UserName = "jack256";
private String Password = "123456";
public void loginInfo (String username,String password){
if(!this.UserName.equals(username)){
System.out.println("用户名错误");
}
if(!this.Password.equals(password)){
System.out.println("密码错误");
}
System.out.println("登录成功");
}
}
public void main(String[] args) {
Login login = new Login();
login.loginInfo("jack256","123456");
}
但是专业一点,处理用户名错误和密码错误我们也可以抛出两种异常,我们可以基于已有的异常类(如 Exception 或者 RunTimeException)进行扩展 ( 继承 ), 自定义创建和我们业务相关的异常类。
语法格式: (自定义异常类,继承自Exception 或者 RunTimeException)
class 自定义异常名称 extends 已有异常类 {
}
具体实现:
//UserNameException类
class UserNameException extends RuntimeException {
public UserNameException() {
}
public UserNameException(String message) {
super(message);
}
}
//PasswordException 类
class PasswordException extends Exception {
public PasswordException() {
}
public PasswordException(String message) {
super(message);
}
}
//LogIn类
public class LogIn {
private String userName = "admin";
private String password = "123456";
public void loginInfo(String userName, String password) throws UserNameException,PasswordException{
if (!this.userName.equals(userName)) {
//System.out.println("名字错误");
throw new UserNameException("用户名错误");
}
if (!this.password.equals(password)) {
//System.out.println("密码错误");
throw new PasswordException("密码错误");
}
System.out.println("登陆成功");
}
public static void main(String[] args) {
LogIn logIn = new LogIn();
try{
logIn.loginInfo("admin1", "123456");
} catch (PasswordException e) {
e.printStackTrace();
System.out.println("PasswordException");
}catch (UserNameException e) {
e.printStackTrace();
System.out.println("UserNameException");
}
}
}
运行结果:
希望对你有帮助