首页 / 资讯中心 / 文章详情

异常 学习笔记

异常 学习笔记 ★ FEATURED ARTICLE
1 概念程序执行中的不正常行为打断了正常流程我们称之为异常。常见的比如算数异常10 / 0、数组越界异常arr[100]、空指针异常等等。1.1 体系结构Java为了方便对不同的异常或错误进行分类管理维护了一个异常的体系结构。· Throwable异常体系的顶层类下面派生出异常和错误两个子类。· Error错误Java虚拟机无法解决的比如JVM中的内部错误、资源耗尽一旦发生回天乏术。· Exception发生后程序员可以通过代码解决的使程序继续执行好比感冒发烧我们今天要学习的异常就是这个。1.2 分类异常通过发生时机的不同可以分为编译时异常编译时期就会显示的异常也称为受检查异常。编译时出的语法性错误不是编译时异常。运行时异常运行时出现的异常即形成了.class文件JVM在执行过程中出现的异常也称为非受检查异常。RunTimeException及其子类都是运行时异常。2 处理程序员编写代码时总会出现一些错误我们就需要程序告知程序员哪里有问题。有两种方法。LBYLLook Before You Leap在你操作前检查即事前防御型简略示例代码int a 10; int b 0; int c 1; if (b ! 0) { System.out.println(a / b); } else { System.out.println(除数不能为0); } if (c ! 0) { System.out.println(a / c); } else { System.out.println(除数不能为0); }缺点正常和检查错误混在一起代码可读性降低。EAFPIt’s Easier to Ask Forgive than Permition事后请求原谅比事前请求同意更简单先操作遇到问题再处理即事后认错型简略示例代码int a 10; int b 0; int c 1; try { System.out.println(a / b); System.out.println(a / c); } catch (ArithmeticException e){ System.out.println(除数不能为0); }优点正常流程和检查错误分开程序员更关注流程代码更易读易理解。Java异常处理的核心就是EAFP。我最讨厌的就是事后道歉杀处理异常主要的5个关键字throw、try、catch、finally、throws2.2 throw抛出指定的异常告诉调用者问题在哪里。代码写法throw new XXXException(异常产生的原因);注意throw必须写在方法体内部。抛出的异常必须是Exception及其子类。如果是RunTimeException及其子类则不用处理交给JVM。如果是编译时异常必须调用者自己手动处理。2.3 throws用于列出方法内部可能抛出的异常告诉调用者。实际上是把处理异常的责任转移给了要使用该方法的人。代码写法修饰符 返回值类型 方法名 (参数列表) throws 异常1, 异常2...注意throws必须放在方法的参数列表的后面。声明的异常必须是Exception及其子类。如果方法内部抛出了多个异常必须都写在throws后面中间用逗号隔开如果多个异常为有继承关系写父类即可。调用声明抛出异常的方法若该方法是编译时异常调用者必须处理该异常或者继续抛出。处理异常可以将光标放在抛出异常的方法上快速处理。2.4 try-catchthrows只是声明了异常程序员要对异常进行捕获和处理就需要用到try-catch关键字。代码写法try { //此处放可能出现异常的代码。 //try中代码也可能不出现异常。 } catch (可能出现的异常类型 e) { //对该异常的处理的代码。 //如果try中代码抛出了异常且和此处catch要捕获的异常一样或try抛出的异常时catch要捕获的异常的子类就会被捕获。 //捕获异常且处理完后跳出try-catch结构try中抛出异常的代码后面的就不会被执行。 } catch (可能出现的异常类型 e) { //catch可以有一个或多个具体看try中会抛出多少异常类型。 } //若异常被捕获完了或没有出现异常流程就会正常来到这里这里的代码就会被执行。 //若捕获时类型不对则异常没有被捕获则异常会被继续往外抛直到由JVM收到后中止程序。流程就不会来到这里。catch中对异常的处理如果是严重的问题如计算金钱应该直接让程序崩溃以减少损失。如果是一般的问题大多数情况则可以记录错误日志并即使通知程序员。如果是可能会回复的问题尝试重试。注意如果多个异常的处理方法完全相同也可以这样catch (ArrayIndexOutOfBoundsException | NullPointerException e)如果异常中存在父子类关系则一定要子类异常在前catch。否则父类会把子类异常接收掉。可以用父类异常捕获一切子类异常但不建议。你不好知道到底捕获了该父类底下的哪个子类异常。Exception是所有异常的父类。2.5 finally有些代码必须在程序结束前执行比如打开了文件就必须在最后关闭但异常的处理会使代码跳转可能导致有些语句执行不到。finally就是解决这个问题的finally里面的语句一定会被执行。代码写法写在最后面finally {…}即可。finally代码的执行顺序在方法返回之前即try-catch内的return语句被执行之前但如果finally中也有return代码则会执行finally中的return语句。所以不建议在finally中写return语句编译器也会报警告。2.6 异常的处理流程方法之间存在互相调用的关系这种调用关系我们可以用调用栈来描述JVM中有一块空间称为“虚拟机栈”专门储存方法之间的调用关系。当本方法内抛出异常而无法被处理时就会沿着调用栈向上传递直到传到main方法还是无法被处理则抛给JVM来处理程序异常终止。可以用e.pringStackTrace()打印出现异常的调用栈。用法catch (ArrayIndexOutOfBoundsException e) {e.printStackTrace();}异常处理流程总结先在try中执行正常流程遇到异常后抛出。若被匹配的catch捕获处理try后面的代码不再被执行。若没有匹配的catch则将异常沿着调用栈传递到上层调用者直到传到main方法还是无法被处理则交给JVM来处理程序异常终止。无论程序是否正常中止finally中的代码都会被最后执行。3 自定义异常Java中内置了丰富的异常类但在实际开发过程中还需要一些我们自己设计的异常。具体做法创建一个自定义异常类继承Exception或RunTimeException。实现一个带有String类型的参数的构造函数参数含义异常出现原因。实例代码public class PasswordException extends Exception { public PasswordException(String message) { super(message); } } //IDEA上设置创建异常就会自动帮你写好。 public class UserNameException extends Exception { public UserNameException(String message) { super(message); } } class LogIn { private String username hcl; private String password 0609; public void logInFo(String username, String password) throws UserNameException, PasswordException { if (!this.username.equals(username)) { throw new UserNameException(用户名错误); } if (!this.password.equals(password)) { throw new PasswordException(密码错误); } System.out.println(登录成功); } } public class Main { public static void main(String[] args) { try { LogIn login new LogIn(); login.logInFo(hcl666, 0609); //这里用户名不对 } catch (UserNameException | PasswordException e) { e.printStackTrace(); } } } 运行结果 UserNameException: 用户名错误 at LogIn.logInFo(Main.java:7) at Main.main(Main.java:20)注意自定义异常一般设置继承Exception或RunTimeException。继承Exception的异常默认是受查异常继承RunTimeException的异常默认时非受查异常。易错小知识NullPointerException是非受查异常。try块后面不一定要跟着catch接一个finally也行。throw关键字也可以抛出error。子类不能抛出比父类声明可能抛出的异常的范围更大的异常。
阅读完成 · 觉得有帮助?
咨询建站