JavaSE学习值之--认识异常(下)

简介: JavaSE学习值之--认识异常(下)

JavaSE学习值之--认识异常(下)+https://developer.aliyun.com/article/1413510

四.异常的处理

1.防御式编程

   错误的代码总是存在且不可避免地,我们要做的就是当程序出现异常的时候及时告诉程序员,来帮助他修改代码,主要有两种思路:

1.LBYL: Look Before You Leap. 在操作之前就做充分的检查. 即:事前防御型

 即对每一个流程都充分想到其可能会发生的错误,及时处理

boolean ret = false;
ret = 登陆游戏();
if (!ret) {
处理登陆游戏错误;
return;
}
ret = 开始匹配();
if (!ret) {
处理匹配错误;
return;
}
ret = 游戏确认();
if (!ret) {
处理游戏确认错误;
return;
}
ret = 选择英雄();
if (!ret) {
处理选择英雄错误;
return;
}

 每进行一步就进行一次检查,但这种方式使正确代码和异常检查的代码混在一起,使得整个代码很混乱,不推荐

2.EAFP: It's Easier to Ask Forgiveness than Permission. "事后获取原谅比事前获取许可更容易". 也就是先操 作, 遇到问题再处理. 即:事后认错型

try {
登陆游戏();
开始匹配();
游戏确认();
选择英雄();
载入游戏画面();
...
} catch (登陆游戏异常) {
处理登陆游戏异常;
} catch (开始匹配异常) {
处理开始匹配异常;
} catch (游戏确认异常) {
处理游戏确认异常;
} catch (选择英雄异常) {
处理选择英雄异常;
} catch (载入游戏画面异常) {
处理载入游戏画面异常;
}

 EAFP的思维简单来说就是管他三七二十一,先执行再说,产生的异常事后处理即可

这种思维是的操作部分和异常处理部分分离,让程序员更加模块化的思考,更有利于代码的编写!!!

在Java中,异常处理主要的5个关键字:throw、try、catch、final、throws。

 在编写程序时,如果程序中出现错误,此时就需要将错误的信息告知给调用者,比如:参数检测

 在Java中,可以借助throw关键字,抛出一个指定的异常对象,将错误信息告知给调用者。具体语法如下:

throw new XXXException("异常产生的原因")

举例:

public static int[] arr ={1,2,3};
    public static int getElem(int index) {
        if(index < 0 || index > arr.length) {
            throw new ArrayIndexOutOfBoundsException(index + "索引不正确,数组越界");
        }
        return arr[index];
    }
    public static void main(String[] args) {
        int[] arr ={1,2,3};
        System.out.println(getElem(0));// 正确  输出1
        System.out.println(getElem(10));// 异常
        System.out.println(getElem(1));// 不输出
    }

注意:

  • throw必须写在方法内部
  • 抛出的异常必须是Exception或Exception的子类
  • 如果抛出的异常是RuntimeException或其子类,不需要处理,直接交给JVM处理
  • 如果抛出的异常是受查异常,必须通过throws进行处理,否则无法通过编译
  • .异常一旦抛出,其后的代码就不会执行

五.异常的捕获

  异常的捕获 就是异常处理的具体方式,包括两种方式

  • try,catch语句
  • throws声明

1.异常声明throws

 处在方法声明时参数列表之后,当方法中抛出编译时异常,用户不想处理该异常,此时就可以借助throws将异常抛 给方法的调用者来处理。即当前方法不处理异常,提醒方法的调用者处理异常。

语法格式: 修饰符 返回值类型 方法名(参数列表) throws 异常类型1,异常类型2...{ }

比如上文的Cloneable接口的实现:

注意:

  • throws必须跟在方法的参数列表之后
  • 声明的异常必须是 Exception 或者 Exception 的子类
  • 方法内部抛出了多个异常,throws也要抛出多个异常,异常之间通过”,“隔开;如果异常之间存在父子关系,只需声明父类异常即可
public class Config {
File file;
// public void OpenConfig(String filename) throws IOException,FileNotFoundException{
// FileNotFoundException 继承自 IOException
public void OpenConfig(String filename) throws IOException{
if(filename.endsWith(".ini")){
throw new IOException("文件不是.ini文件");
}
if(filename.equals("config.ini")){
throw new FileNotFoundException("配置文件名字不对");
}
// 打开文件
}
public void readConfig(){
}
}
  • 调用声明抛出异常的方法时,调用者必须对该异常进行处理,或者继续使用throws抛出

2 try-catch捕获并处理

 throws声明异常并没有处理异常,只是将异常交给调用者去处理,一直传递给JVM虚拟机;要想真正处理异常,就需要try-catch语句

注意:

1.try中存放可能出现异常的代码,也就是说不一定会抛出异常

2.catch()存放异常的类型,{}内部存放处理的代码,处理完成后会继续执行后续代码;如果没有捕获到异常,则catch里的语句并不会被执行

3.finally中的语句一定会被执行,

4.打印异常有三种

5.如果抛出异常类型与catch时异常类型不匹配,即异常不会被成功捕获,也就不会被处理,继续往外抛,直到 JVM收到后中断程序----异常是按照类型来捕获的

 

6.如果异常之间存在父子关系,子类异常被捕获时在前,父类在后,如果顺序颠倒,子类异常的捕获就没有任何意义了

public static void main(String[] args) {
int[] arr = {1, 2, 3};
try {
System.out.println("before");
arr = null;
System.out.println(arr[100]);
System.out.println("after");
} catch (Exception e) { // Exception可以捕获到所有异常
e.printStackTrace();
}catch (NullPointerException e){ // 永远都捕获执行到
e.printStackTrace();
}
System.out.println("after try catch");
}

7.无论如何,finally中的代码一定会被执行

public static int[] arr ={1,2,3};
    public static int getElem(int index) {
        return arr[index];
    }
    public static void main(String[] args) {
        int[] arr ={1,2,3};
        try{
            System.out.print(getElem(100));// 异常
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            System.out.println("finally中的代码一定会被执行");
        }
}

 在写程序时,有些特定的代码,不论程序是否发生异常,都需要执行,比如程序中打开的资源:网络连接、数据库 连接、IO流等,在程序正常或者异常退出时,必须要对资源进进行回收。另外,因为异常会引发程序的跳转,可能 导致有些语句执行不到,finally就是用来解决这个问题的。

思考:那我们该如何记录并处理异常呢?什么时间去处理异常呢?

 在目前我们所写的代码中,常常采取记录错误日志的方式来记录异常,通过编译器的报错告诉程序员出错的地方

六.如何设计一个自定义类型的异常?

 将你可能出现的异常设计为一个继承ExceptionRunTimeException的类,添加一个带参数的构造方法(用于打印错误信息),在调用时,一旦出错就抛出对应的异常即可

 注意:继承Exception的类是受查异常,必须在调用的方法声明中添加throws该异常

继承RunTimeException的类是非受查异常,不需要添加声明

e.printStackTrace();打印异常信息

class UsernameException extends RuntimeException {
    public UsernameException(String message) {
        super(message);
    }
}
class PasswdException extends RuntimeException {
    public PasswdException(String message) {
        super(message);
    }
}
class Login {
    private String Username;
    private String Passwd;
    public static void logininfo(String Username,String Passwd) {
        if(!Username.equals("admin")) {
            throw new UsernameException("用户名错误");
        }else if(!Passwd.equals("123456")) {
            throw new PasswdException("密码错误");
        }
    }
}
public class Test1 {
    public static void main(String[] args) {
        try {
            Login.logininfo("admin2","123456");
        }catch (UsernameException ex) {
            ex.printStackTrace();
        }catch (PasswdException ex) {
            ex.printStackTrace();
        }
    }
}

异常总结:

1.throw抛出一个异常

 用于参数检测  一旦出错就可以达到终止程序运行的操作

比如传递数组和数组的下标

1.如果数组是null  直接抛出空指针异常,程序停止运行

2.如果下标超过数组的范围,直接抛出数组越界异常,程序停止运行

之前:出现这种错误,只打印错误的信息,比如arr == null  sout("数组为空"),这种方式太温柔了,只告诉你有错误,但不会终止运行;直接抛异常,既能知道错误的信息,又能终止程序的运行

2.异常处理关键字的理解

throws:是一种甩锅行为,通过在方法的生命中添加throws+异常种类,将这个可能出现的异常交给调用者处理,而调用者可以在他的方法声明时添加throws异常,交给jvm去处理,就是一种甩锅,但很方便,不需要设置try catch

try catch finally:   throws并没有处理异常,只是甩锅给其他人;try catch是一种自己解决异常的方法,通过catch捕获异常并记录异常的日志  所谓的捕获异常就是解决该异常(异常都是被抛出的,catch接受抛出的异常,给他限制在笼子里,这样就没有异常了)

finally:有些代码无论程序是否异常都必须要被执行(比如电脑就算连不上网,也要能看到界面啊?再比如,校园网欠费,无法上网,但是我还能打开缴费网站),如果打不开那我怎么解决上网的问题?所以finally就是用来解决这种任何情况下都要执行的代码(也就是说无论你欠不欠费都能打开缴费网站)

对于已受查异常来说,其异常会在编译的时候发现,必须通过tycatch语句捕获或者在方法签名使用throws抛出

3.异常处理的流程

  • 程序先执行 try 中的代码 如果 try 中的代码出现异常, 就会结束 try 中的代码,
  • 看和 catch 中的异常类型是否匹配. 如果找到匹配的异常类型, 就会执行 catch 中的代码
  • 如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者.
  • 无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行).
  • 如果上层调用者也没有处理的了异常, 就继续向上传递.
  • 一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止

目录
相关文章
|
6月前
|
Java
请解释Java中的异常处理机制,并给出使用try-catch块的示例。
请解释Java中的异常处理机制,并给出使用try-catch块的示例。
143 0
|
1月前
|
IDE Java 开发工具
Java“未封闭的 String 表达式”怎么解决
要解决Java中的“未封闭的 String 表示”问题,需检查并修正字符串字面量,确保每个字符串被正确地用双引号括起来。若字符串跨越多行,可使用字符串连接操作符(+)或引入文本块(JDK 13 及以上版本)。这能帮助避免语法错误,并使代码更整洁易读。
|
1月前
|
Java
Java“缺少返回语句”解决
在 Java 中,错误信息“缺少返回语句”表示方法应返回某种类型但未在所有路径中提供返回值,导致编译错误。解决方法包括:确保每个控制路径中有返回值;处理所有分支和异常情况;或将方法声明为 `void` 类型以避免返回值需求。
|
1月前
|
Java 编译器
Java“无效的方法声明;需求返回类型”怎解决
要解决Java中的“无效的方法声明;需要返回类型”错误,需为方法指定正确的返回类型。检查方法签名,添加如`void`、`int`、`String`等类型,并确保方法体内正确使用`return`语句。这能帮助Java编译器理解和验证方法的行为。遵守这些规则,可以避免语法错误并确保程序正常运行。
|
Java 编译器 API
【小家Java】Lombok的使用详解(最详尽的解释,覆盖讲解所有可用注解),解决@Builder.Default默认值问题(下)
【小家Java】Lombok的使用详解(最详尽的解释,覆盖讲解所有可用注解),解决@Builder.Default默认值问题(下)
【小家Java】Lombok的使用详解(最详尽的解释,覆盖讲解所有可用注解),解决@Builder.Default默认值问题(下)
java.lang.NullPointerExceptionMybatisPlus出现,测试,java.lang.NullPointe,空指针异常,public方法少写了一个字段,没加注解
java.lang.NullPointerExceptionMybatisPlus出现,测试,java.lang.NullPointe,空指针异常,public方法少写了一个字段,没加注解
|
6月前
|
监控 Java
JAVASE---异常知识补充
Java异常处理涉及关键字try, catch, finally, throw, throws。示例中展示了如何处理`ArithmeticException`。在`Demo01`,尝试除以零并主动抛出异常,通过不同catch块捕获。`Demo02`中,方法`test`可能抛出异常,并通过`throws`声明。`Test`用try-catch处理除零错误,并将异常转换为`RuntimeException`。自定义异常可通过继承`Exception`类实现,流程包括创建异常类、抛出异常对象、捕获处理异常。
32 1
|
6月前
|
Java 编译器 程序员
JavaSE学习值之--认识异常(上)
JavaSE学习值之--认识异常
58 0
java定义一个变量后调用该变量提示Unknown class
java定义一个变量后调用该变量提示Unknown class
|
Java
Java中如何循环输出对象、属性和值【亲测可用】、反射机制
Java中如何循环输出对象、属性和值【亲测可用】、反射机制
784 0