异常是为了反馈和处理/解决问题设计的一套机制。异常的顶级父类是Throwable,它有两个子类:Error、Exception。下面分别详细介绍两者。java
一、Exception的定义:表示在合理的应用程序中出现的能够处理的问题。ide
二、异常的分类:优化
三、异常的处理方式:this
四、自定义异常:若是在实际开发过程当中,遇到了问题可是在java中没有对应的异常,那么就须要本身定义一个异常。spa
若是定义的是一个编译时异常,写一个类继承Exception。设计
若是须要定义一个运行时异常,须要继承RuntimeException。日志
示例以下:code
public class ExceptionDemo2 {public static String readTxtFile(String path) throws PathNotExistException, FileFormatException { // 路径问题 if (!new File(path).exists()) // 须要将抛出的问题以对象的形式来进行封装 // 若是跑出了异常对象,那么该方法的后续代码再也不执行 throw new PathNotExistException("亲,这个路径不存在哦~~~"); // 文件格式不正确 if (!path.endsWith(".txt")) { // xxxx.xxx.xxx int index = path.lastIndexOf('.'); String suffix = path.substring(index + 1); throw new FileFormatException("须要一个txt文件,可是传入一个" + suffix + "文件"); } // 正常读取 return "读取成功~~~"; } } @SuppressWarnings("serial") class PathNotExistException extends Exception { // private String message; public PathNotExistException(String msg) { // this.message = msg; super(msg); } // public String getMessage() { // return message; // } } @SuppressWarnings("serial") class FileFormatException extends Exception { public FileFormatException(String msg) { super(msg); } }
五、异常的捕获方式orm
public static void main(String[] args) /* throws FileFormatException */ { //1.分别处理异常 // try { // String msg = readTxtFile("D:\\a.bmp"); // System.out.println(msg); // } catch (PathNotExistException e) { // // 处理问题 // // System.out.println("捕获到了一个问题:路径不存在~~~"); // System.out.println(e.getMessage()); // } catch (FileFormatException e) { // // System.out.println("文件格式不正确~~~"); // System.out.println(e.getMessage()); // } //2. 统一处理 // try { // String msg = readTxtFile("D:\\a.bmp"); // System.out.println(msg); // } catch (Exception e) { // System.out.println(e.getMessage()); // } //3.分组处理 try { String msg = readTxtFile("D:\\a.bmp"); System.out.println(msg); } catch (PathNotExistException | FileFormatException e) { // 表示捕获PathNotExistException或者是FileFormatException System.out.println(e.getMessage()); } }
六、异常对方法的重载没有影响。对象
// 异常对方法的重载的有影响吗? class A { public void m() throws IOException { System.out.println("A m()"); } public void m(int i) throws ParseException { System.out.println("A m(int)"); } } class B extends A { public void m() throws EOFException, FileNotFoundException, NullPointerException { System.out.println("B m()"); } }
七、异常对方法重写的影响:在方法重写的时候,子类中重写的方法抛出的编译时异常不能超过父类方法抛出的编译时异常的范围。即:子类不能抛出比父类更高级的异常。
八、finally:不管前边的代码执行成功与否,finally中的代码都会执行一次。内存中的栈能够分为计算区和结果区;当try检测到finally时,程序仍是会顺序执行。只不过会返回结果会延迟,此时,当执行到try中的return语句时,会先将结果存储到结果区,等到finally程序执行完毕后,再将结果返回。若是try 和 finally都有return语句,这以finally返回语句为准。例如以下实例返回结果为5。
public static void main(String[] args) { System.out.println(m()); } private static int m() { int i = 5; try { // 代码依然是从上到下顺次执行的 // 在执行try以前会先检测是否有finally // 若是有finally,那么会将try中的返回过程推后 // 栈内存的结构:计算区域,结果区域 -> 栈帧 // 实际执行过程:try->finally->方法返回实际结果 // 先执行try中的代码 // 执行return语句,只是将结果放入结果区域 // i在计算区域继续自增为6 return i++; } finally { // 继续执行finally // i在计算区域继续自增为7 // 执行完成finally,方法会将结果区域的值进行返回 i++; System.out.println("finally:" + i); } }
当返回的是一个引用类型时,因为finally中值的改变是改变的结果区的数据,所以,此时会影响到返回结果。例如:
public class ExceptionDemo8 { public static void main(String[] args) { System.out.println(m()); } private static Student m() { Student s = new Student(); try { s.setName("翠花"); s.setAge(18); // 由于结果区域存储的是s的地址 return s; } finally { s = new Student(); s.setName("周星星"); s.setAge(80); } } } class Student { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } }
此时,返回的结果是:周星星,80
九、若是方法抛出的是父类异常,那么使用的时候也必须捕获一个父类异常;再捕获异常的时候,必须先捕获子类异常后捕获父类异常。缘由:若是先捕获父类异常,父类异常中已经包含子类异常,就会报错了。
十、当项目处在开发期间是,若是项目中出现了异常,打印这个异常的栈轨迹,而后根据这个轨迹进行调错;若是项目已经上线,出现了异常,记录错误日志。
一、表示严重的错误。
二、出现以后不能处理。
三、出现以后只能尽可能优化代码,减小错误出现的概率。