首页 > 基础资料 博客日记
Java——异常
2024-07-31 04:00:05基础资料围观196次
目录
一、什么是异常
在我们日常生活中,我们可能会生病,会头疼,会肚子疼,打球的时候也可能会受伤。再程序中也是一样,运行时难免会出现一些奇奇怪怪的问题。
在Java中,将程序执行过程中发生的不正常行为称为异常。
例如:
算数异常
//算数异常
System.out.println(10 / 0);
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Test.main(Test.java:4)
数组越界异常
//数组越界异常
int[] arr = {1,2,3,4};
System.out.println(arr[4]);
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4
at Test.main(Test.java:8)
空指针异常
//空指针异常
String str = null;
System.out.println(str.length());
Exception in thread "main" java.lang.NullPointerException
at Test.main(Test.java:12)
在Java中不同类型的异常,都有与其对应的类来进行描述。
二、异常的体系结构
感觉异常还是挺多的,那在Java中是怎么分类管理的呢?构建一个异常的体系结构。
从图中可以看到:
Throwable:是顶层类,其有两个子类Error Exception.
Error 是指Java虚拟机无法解决的严重问题,如StackOverflowError栈溢出,OutOfMemoryError堆溢出。
Exception: 程序员可以通过代码进行处理,让程序继续执行。
异常分类
异常可能在编译时发生,叫编译时异常,也叫受检查异常。
如:java.lang.CloneNotSupportedException
public class Dog {
public String name;
public String age;
public Dog clone() {
return (Dog) super.clone();
}
}
在运行时发生,叫运行时异常,也叫非受检查异常。
RunTimeException以及其子类对应的异常,都称为运行时异常。
比如:
NullPointerException、
ArrayIndexOutOfBoundsException、ArithmeticException
注意:
编译时出现的语法性错误,不能叫做异常。
运行时异常时经过编译生成字节码Class文件,再有Java执行过程中出现的错误。
三、异常的处理过程
事前防御型:在操作之前就做充分的检查。代码比较混乱,正常操作与处理错误的操作混合。
//以和平精英为例
Boolean login = loginGame();
if(login==false) {
处理登录失败的错误;
return;
}
login = matchTeammates();
if(login==false) {
处理匹配队友失败的错误;
return;
}
login = loadingScreen();
if(login==false) {
处理加载地图失败的错误;
return;
}
...
事后认错型:先操作,遇到问题再处理解决。正常处理流程和错误处理流程分开,代码清晰易理解。
try{
loginGame();
matchTeammates();
loadingScreen();
}catch (loginGameException e){
处理登录失败的错误;
}catch (matchTeammatesException e){
处理匹配队友失败的错误;
}catch (loadingScreenException e){
处理加载地图失败的错误;
}
....
1.异常的抛出
throw ,抛出一个指定的异常对象,将错误的信息传递给调用者。
throw new xxxException("异常产生的原因")
public class Test {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
getArrayElement(arr,1);
}
public static int getArrayElement(int[] arr,int index) {
if(arr==null) {
throw new NullPointerException("数组空指针异常");
}
if(index<0 || index>arr.length-1) {
throw new IndexOutOfBoundsException("数组下标越界");
}
return arr[index];
}
}
注意y一下几点:
- throw必须写在方法体的内部
- 抛出的对象必须是Exception / Exception 的子类
- 如果抛出的是运行时异常 RunTimeException / RunTimeException 的子类,则可以不用处理,直接交给JVM来处理
- 如果抛出的是编译时异常,用户必须处理,否则无法通过编译
- 异常一旦抛出,其后的代码就不会执行
2.异常的捕获
- throws异常声明
- try - catch 捕获处理
3.throws异常声明
用于当前的方法不处理异常,提醒调用者来处理异常。
修饰符 返回值类型 方法名(参数列表)throws 异常类型1,异常类型2 ... {
...
}
以上面的小狗类为例子:
public class Dog {
public String name;
public String age;
public Dog clone() throws CloneNotSupportedException{
return (Dog) super.clone();
}
//throws抛给调用者,此时为Test
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Dog dog = new Dog();
dog.clone();
//此时Test也不处理,抛给JVM来处理。
//一旦交给JVM处理,程序就终止了!
}
}
注意事项:
- throws必须出现方法的参数列表后
- 声明的异常必须是Exception,及其子类,不能是Error
- 如果需要抛出多个异常,则异常之间用逗号隔开,如果抛出的异常有父子关系,则直接声明父类即可!
- 使用throws,调用者必须对该异常进行处理,或继续使用throws
4.try - catch 捕获处理异常
由上可知throws并没有对异常进行有效的处理,此时就需要用到try - catch了!
try {
//可能会出现异常的代码
}catch(异常类型1 e) {
// 对try中的代码块出现的异常类型1进行捕获
//没出现异常就直接跳过了
}catch(异常类型2 e) {
// 对try中的代码块出现的异常类型2进行捕获
//没出现异常就直接跳过了
}
public static void main(String[] args) {
int[] arr = {1,2,3,4};
System.out.println("异常处理开始-------");
try{
System.out.println(arr[21]);
arr=null;
System.out.println(arr.length);
}catch (NullPointerException e) {
e.printStackTrace();
}catch (ArrayIndexOutOfBoundsException e){
e.printStackTrace();
}
System.out.println("异常处理结束-------");
}
为啥这个异常信息在最后输出?因为和System.out.println()输出的方式不一样。
注意事项:
- try里只要哪一行抛出异常,其后面的代码则不再执行
- 出现的异常会与catch中的异常类型进行一 一匹配,一致则捕获,否则继续往上抛,直到JVM
- 如果异常之间具有父子关系,子一定要在父前,因为父亲可以接受子类的出现的异常,那么子类就没有了意义。
- 建议不同的异常,分开写,不必直接写Exception
- 只会抛出一个异常,不会抛出多个异常。
5.finally
再写程序时,有些特定的代码,无论是否发生异常,都需执行。如 打开的文件资源,组后都需关闭,对资源进行回收。也是因为出现异常,有些代码不能执行到。
try {
}catch (异常类型 e) {
}finally {
//无论发生异常与否,都会执行到。
}
那么既然finally 和 try-catch-finally后的代码都会执行到,那么为啥还要有finally?
返回数据,如果正常输入,则s 无法关闭。
public class Test {
public static void main(String[] args) {
printFunc();
}
private static int printFunc() {
Scanner s = new Scanner(System.in);
try {
int a = s.nextInt();
return a;
}catch (InputMismatchException e) {
e.printStackTrace();
}
s.close();
return 0;
}
}
所以有finally
public class Test {
public static void main(String[] args) {
printFunc();
}
private static int printFunc() {
Scanner s = new Scanner(System.in);
try {
int a = s.nextInt();
return a;
}catch (InputMismatchException e) {
e.printStackTrace();
}finally {
s.close();
}
return 0;
}
}
6.异常处理流程总结
- 程序先执行 try 中的代码
- 如果 try 中的代码出现异常, 就会结束 try 中的代码, 看和 catch 中的异常类型是否匹配.
- 如果找到匹配的异常类型, 就会执行 catch 中的代码
- 如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者.
- 无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行).
- 如果上层调用者也没有处理的了异常, 就继续向上传递.
- 一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止
四、自定义异常
虽然Java中异常类有许多了,但是并不能完全表示实际开发中所遇到的一些异常,此时就需要我们自己定义一些异常了。
- 自定义异常通常会继承Exception(默认为受检查的异常)或RuntimeException(为非受检查的异常)
实现一个用户登录功能,登录用户名或密码错误采用自定义异常类处理。
public class Test {
public static void main(String[] args) {
try {
login("zxh","123456");
} catch (UserNameException e) {
throw new RuntimeException(e);
} catch (PasswordException e) {
throw new RuntimeException(e);
}
}
public static void login(String name, String pwd) throws PasswordException, UserNameException {
if(!name.equals("zxh")) {
throw new UserNameException("用户名错误!");
}
if(!pwd.equals("123456")) {
throw new PasswordException("密码错误!");
}
System.out.println("登录成功");
}
}
public class PasswordException extends Exception{
//因为写了hrow new PasswordException("密码错误!"); 传递了参数。
public PasswordException(String message) {
super(message);
}
}
public class UserNameException extends Exception{
//传递了参数
public UserNameException(String message) {
super(message);
}
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签: