🌟1.什么是异常?
异常:程序执行过程中发生不正常行为称为异常
☀️ 异常的结构体系
Throwable:是异常体系的结构类,其派生出的两个重要的子类,Error和Exception;Exception:异常后程序员可以通过代码进行处理,使程序继续执行;Error:指虚拟机无法解决的严重问题,比如:JVM的内部错误,资源耗尽等。
示例:
1️⃣ 算术异常(ArithmeticException):
public static void main(String[] args) {
System.out.println(1/0);
}
2️⃣空指针异常(NullPointerException)
public static void main(String[] args) {
int[] a=null;
System.out.println(a[0]);
}
3️⃣数组下标越界异常(ArrayIndexOutOfBoundsException)
public static void main(String[] args) {
int[] a={1,2,3,4};
System.out.println(a[5]);
}
注意:
语法错误不等于异常
*
🌟2.异常的分类有哪些?
根据发生的时机不同分类:
异常的分类根据发生时机的不同,分为编译时异常和运行时异常。
☀️编译时异常(受查异常)
编译时异常:在程序编译期间发生的异常称为编译时异常,也可以称为受查异常。
特点:必须进行显示处理,可以通过try—catch进行捕获并处理,或者使用throws声明可能抛出的异常,将异常上移交给调用者。如果不处理,程序编译就无法通过。
示例:
不支持克隆异常:
☀️运行时异常(非受查异常)
运行时异常:在程序运行时期间发生的异常,也称为非受检查异常。
特点:无需显示处理,也可以和编译时异常处理一样。但JVM不会检查他,即使没有用try—catch,throws声明,编译也会通过。
示例:
算术异常:
public static void main(String[] args) {
System.out.println(10/0);
}
🌟3.如何处理异常?
异常处理的五个关键字:throw,throws,try,catch,finally
☀️抛出异常:throw
异常的抛出:可以理解为自己手动抛出异常。
示例:
public static void main(String[] args) {
//如果4%2==0为真,那么抛出异常
if (4%2==0){
throw new ArithmeticException();
}
}
结果:
作用:在Java中,可以借助throw关键字,抛出一个指定的异常对象,将错误信息告知给调用者。可以检验该程序是否发生错误或者异常情况;也可以通过throw来创建自己的异常类,也就是自定义异常。 注意事项:throw通常是在方法体内部使用的;可以在异常中传参;
throw抛出的类,可以是Throwable类(不推荐),包括Exception或者Error以及其子类;如果抛出异常,那么其后面的代码无法执行。
异常要在方括号中的最后一行,否则报错;
☀️异常的捕获
🌞声明异常:throws
throws:用于声明可能会抛出的异常,当方法中抛出编译时异常,如果用户不想处理异常,可以交给JVM处理,也可以提醒方法的调用者处理异常。
> throws的语法格式:
> 修饰符 返回值类型 方法名(参数列表)throws 异常类型1,异常类型2...{
.......
>}
示例:
像之前的不克隆异常
声明当前可能抛出的异常,我们无需再处理,但这里的异常没有被处理,只是交给了JVM处理
throws声明要在方法的参数列表后面;可以声明多个异常类型;在编译时异常使用throws可以不用处理异常,但在运行时异常时还是需要处理异常;声明的异常可以是Throwable类,以及其子类Expcetion或者Error及其子类。
🌞try-catch的捕获并处理
⚪️语法格式:
- try-catch-finally的语法格式:
try{
//可能出现异常的代码
}catch(异常1 e){
//捕获异常1
}catch(异常2 e){
//捕获异常2
}finally{
//资源的释放
}
可以有多个catch单个可能出现的异常,也可以单个catch多个可能出现的异常;catch后面的异常要加上一个e,e是对exception起的变量名称,e也可以用exception;
*
public static void main(String[] args) {
try{
System.out.println(10/0);
}catch(Exception exception){
System.out.println("捕获运行时异常");
}
}
try-catch也可以捕获Error(错误),但是不推荐。
看一下下面的图片,我们知道该代码会出现算数异常,接下来我们用try-catch对其·进行处理
🔴处理异常
public static void main(String[] args) {
try{
System.out.println(10/0);
}catch(ArithmeticException e){
//捕获异常
System.out.println("捕获算术异常");
}
//捕获异常成功,其后面的代码可以执行
System.out.println("1111");
}
如果抛出的类型,与catch捕获的类型不同,那么异常没有被,将抛出异常
public static void main(String[] args) {
try{
System.out.println(10/0);
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("捕获");
}
}
🔵try-catch内抛出异常
💙在try内抛出异常
public static void main(String[] args) {
try{
throw new ArithmeticException();
}catch(ArithmeticException e){
System.out.println("捕获");
}
System.out.println("111");
}
如果在try内直接抛出异常,该异常也可以被处理在catch内抛出异常
public static void main(String[] args) {
try{
System.out.println(10/0);
}catch(ArithmeticException e){
throw new ArithmeticException();
}
System.out.println("111");
}
💛*在try-catch内同时抛出异常**
既然catch写多个可能出现的异常,那么会抛出多个异常吗?我们来看一下
public static void main1(String[] args) {
//同时抛出多个异常
try{
System.out.println("111");
int[] a={1,2,3};
System.out.println(a[4]);
System.out.println("123");
System.out.println(10/0);
}catch(ArithmeticException e){
System.out.println("捕获到算术异常");
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("捕获到数组越界异常");
}
System.out.println("1111");
}
父类可以捕获子类的异常吗❓
瞅瞅下面的代码👀,运行时异常(RuntimeException)是算术异常的父类,而Exception是所有类的父类:
public static void main(String[] args) {
try{
System.out.println(10/0);
}catch(RuntimeException e){
System.out.println("捕获运行时异常");
}
try{
System.out.println(10/0);
}catch(Exception e){
System.out.println("捕获异常");
}
}
答案显而易见是可以的✔️。既然如此Exception是所有异常的父类时可以捕获所有异常的;那Exception的父类Throwable也可以捕获异常吗❓
父类可以捕获子类的异常,使用Exception可以捕获所有异常,也可以使用Throwable来捕获异常;
如果第一个catch的异常是第二个catch的异常的子类,这样可以吗❓如果可以的话,那他是捕获的是父类的异常还是子类的异常❓那如果第一个catch的异常是第二个catch的异常的父类呢❓
我们来看一下:
1.子类在前,父类在后
2.父类在前,子类在后
可以子类在前,父类在后,不可以子类在后,父类在前。可以理解为,如果父类在前,父类包含子类,子类没有存在的必要了;如果有其对应的子类异常,子类优先;
catch(或使用)
public static void main(String[] args) {
try{
System.out.println("111");
int[] a={1,2,3};
System.out.println(a[4]);
System.out.println("123");
System.out.println(10/0);
}catch(ArithmeticException | ArrayIndexOutOfBoundsException e){
System.out.println("捕获到异常");
}
System.out.println("1111");
}
如上代码所示:
也可以通过或来,只写一个catch来捕获多个异常,但这种不推荐;使用或的话,与异常之间不能存在父子类关系;
咦,看了这么多,我发现了,只要抛出了异常,后面的代码就无法执行了,那如果我有一定要执行的语句呢,应该怎么办❓这个时候就要finally派上用处了
finally
finally:finally是对在程序正常或异常退出时,必须对资源进行回收。并且如果因为异常,有些执行语句,执行不到,可以用finally来解决。并且可以执行必要的清理操作,保持程序的一致性和稳定性。
无论怎么样,finally都会被执行到;如果捕获异常失败,先执行fianlly,在抛出异常;
🌟4.自定义异常
自定义异常:我们自己定义维护符合我们实际需要的异常结构。
示例:我们实现一个用户登入功能,我们需要输入用户名和密码,在输入过程中,我们可能会出现错误的情况,用我们之前学的知识写一下,代码如下:
class Login{
private String userName;
private String passWord;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
//登入
public void loginof(String userName,String passWord){
if(!this.userName.equals(userName)){
System.out.println("用户名错误!");
}
if(!this.passWord.equals(passWord)){
System.out.println("密码错误!");
}
}
}
public class Test {
public static void main(String[] args) {
Login login=new Login();
login.setUserName("a");
login.setPassWord("111");
login.loginof("a","123");
}
}
他的密码输入错误,结果输出如上。如果我们想要在我们输错时报出异常,这时,我们可以自己定义一个异常,用户名输入错误异常和密码输入错误异常;
我们可以定义一个输入错误异常类和密码输入错误异常类来继承运行时异常
public class UserNameException extends RuntimeException{
public UserNameException(){
super();
}
public UserNameException(String m){
super(m);
}
}
public class PassWordException extends RuntimeException{
public PassWordException(){
super();
}
public PassWordException(String m){
super(m);
}
}
抛出异常
public void loginof(String userName,String passWord){
if(!this.userName.equals(userName)){
throw new UserNameException("用户名错误");
}
if(!this.passWord.equals(passWord)){
throw new PassWordException("密码错误!");
}
}
}
自定义异常可以继承RuntimeException也可以继承Exception;继承Exception是默认编译时异常;继承RuntimeException是默认运行时异常。