基本异常

是指阻止当前的方法或者作用域继续执行的问题
普通问题:在当前的环境下能够获得足够的信息,总能处理这个错误,但是异常情形无法获得的必要的信息来解决问题
抛出异常:从当前的环境跳出,把问题提交给上一级环境。
首先,就像创建其他对象一样,先使用new在堆上创建异常对象,然后当前的执行路径被终止。并且从当前的环境中弹出对异常对象的引用,这个时候,异常处理机制接管程序,并且寻找一个恰当的位置来继续执行程序(并不是说异常发生,程序就不会继续执行了)
这个恰当的位置就是异常处理程序,它的任务就是将程序从错误状态中恢复回来,要么程序继续执行,要么换一种方式继续执

异常参数

所有的标准异常类都有两个构造器:一个是默认构造器,另一个是接受字符串作为参数
从效果上看throw就像是从方法中返回的,可以将它看成一种不同的返回机制,另外还可以用抛出异常的方式从当前的作用域退出。

try块

如果在方法内部抛出了异常,这个方法就在抛出异常之后就结束了
如果不希望就此结束,可以在方法内部设置一个try块,来捕获异常,因为这个块里尝试各种方法调用(可能产生异常的),是跟在try后面的普通程序代码块:try{}

异常处理程序catch

抛出的异常必须在某个地点得到处理,这里就是异常处理程序,并且对于每个捕获的异常,都得到相应的处理程序
它紧跟在try块后面,用关键字catch表示

终止和恢复

终止模型:一旦异常被抛出,就会终止程序
恢复模型:通常是异常被处理之后,可以继续程序的运行的(catch中不要throw)

创建自定义异常

要自己定义异常,必须从已有的异常类中继承,而且最好选择意思相近的异常类继承

  1. public class InheritingExceptions {
  2. public void f() throws SimpleException {
  3. System.out.println("Throw SimpleException from f()");
  4. throw new SimpleException(); //异常对象引用
  5. }
  6. public static void main(String[] args) {
  7. final InheritingExceptions i = new InheritingExceptions();
  8. try {
  9. i.f();
  10. } catch (SimpleException e) {
  11. System.out.println("Caught it");
  12. }
  13. }
  14. }

对异常来说,最重要的就是部分就是类名和错误提示
也可以为自定义异常创建一个带参数的构造器

  1. class MyException extends Exception{
  2. public MyException(){}
  3. public MyException(String msg){super(msg);}
  4. }
  5. public class FullConstructor {
  6. public static void f() throws MyException {
  7. System.out.println("Throwing MyException from f()");
  8. throw new MyException();
  9. }
  10. public static void g() throws MyException {
  11. System.out.println("Throwing MyException from g()");
  12. throw new MyException("Originated in g()");
  13. }
  14. public static void main(String[] args) {
  15. try {
  16. f();
  17. } catch (MyException e) {
  18. e.printStackTrace();
  19. }
  20. try {
  21. g();
  22. } catch (MyException e) {
  23. e.printStackTrace();}}}

捕获所有异常

通过只写一个异常处理程序来捕获所有类型的异常。通过捕获异常类型的基类Exception,最好将其放在处理程序列表的末尾

栈轨迹

  1. public class WhoCalled {
  2. static void f(){
  3. try {
  4. throw new Exception();
  5. } catch (Exception e) {
  6. for (StackTraceElement stackTraceElement : e.getStackTrace()) {
  7. System.out.println(stackTraceElement.getMethodName());
  8. }
  9. }
  10. }
  11. static void g(){f();}
  12. static void h(){g();}
  13. public static void main(String[] args) {
  14. f();
  15. System.out.println("------------");
  16. g();
  17. System.out.println("------------");
  18. h();
  19. }

重新抛出异常

把刚捕获的异常重新抛出,重抛异常会把异常抛给上一级环境中的异常处理程序,同一个try块的后续catch字句将被忽略。如果只是把当前的异常重新抛出,那么printStackTrace()方法显示的是原来异常抛出点的调用栈信息,而不是重新抛出点的信息

  1. public class ReThrowing {
  2. public static void f() throws Exception {
  3. System.out.println("originating the exception in f()");
  4. throw new Exception("thrown in f()");
  5. }
  6. public static void g() throws Exception {
  7. try {
  8. f();
  9. } catch (Exception e) {
  10. System.out.println("Inside g(),e,printStackTrace()");
  11. e.printStackTrace();
  12. throw e;
  13. }
  14. }
  15. public static void h() throws Exception {
  16. try {
  17. f();
  18. } catch (Exception e) {
  19. System.out.println("Inside h(),e.printStackTrace()");
  20. e.printStackTrace();
  21. throw (Exception) e.fillInStackTrace(); //调用这个方法就成了异常的新发生地
  22. }
  23. }
  24. public static void main(String[] args) {
  25. try {
  26. g();
  27. } catch (Exception e) {
  28. System.out.println("Main,printStackTrace()");
  29. e.printStackTrace();
  30. }
  31. try {
  32. h();
  33. } catch (Exception e) {
  34. System.out.println("Main,printStackTrace()");
  35. e.printStackTrace();
  36. }
  37. }
  38. }
  1. class OneException extends Exception{
  2. public OneException(String s){super(s);}
  3. }
  4. class TwoException extends Exception{
  5. public TwoException(String s){super(s);}
  6. }
  7. public class RethrowNew {
  8. public static void f() throws OneException {
  9. System.out.println("originating the exception in f()");
  10. throw new OneException("throw from f()");
  11. }
  12. public static void main(String[] args) {
  13. try {
  14. try {
  15. f();
  16. } catch (OneException e) {
  17. System.out.println("Caught in inner try, e.printStackTrac()");
  18. e.printStackTrace();
  19. throw new TwoException("from inner try");
  20. }
  21. }
  22. catch (TwoException e){
  23. System.out.println();
  24. e.printStackTrace();
  25. }
  26. } //组后异常仅仅知道自己来自main(),而且对f()一无所知
  27. }

Java标准异常

Throwable这个类可以作为任何异常被抛出的类,它可以分为两种类型
Error:表示编译时和系统错误,一般不需要关心
Exception:是可以被抛出的基本类型,在Java类库,用户方法,或者运行时的故障都可能抛出Exception异常
通常关心的基本类型时Exception

RuntimeException

属于运行时的错误有很多,他们会自动的被Java虚拟机抛出

使用finally进行清理

finally子句总能运行

  1. class ThreeException extends Exception{}
  2. public class FinallyWorks {
  3. static int i = 0;
  4. public static void main(String[] args) {
  5. while (true){
  6. try{
  7. if (i++ == 0){
  8. throw new ThreeException();
  9. }System.out.println("No exception");
  10. }catch (Exception e){
  11. System.out.println("Three Exception");
  12. }finally { //finally语句总能执行
  13. System.out.println("In finally clause");
  14. if (i == 2){
  15. break;
  16. }
  17. }
  18. }
  19. }
  20. }

如果异常抛出了但是没有被捕获,就会出现下种情况

  1. public class Switch {
  2. private boolean state = false;
  3. public boolean read(){return state;}
  4. public void on(){state = true;
  5. System.out.println(this);}
  6. public void off(){state = false;
  7. System.out.println(this);}
  8. @Override
  9. public String toString() {return state ? "on" : "off";}
  10. }
  11. class OnOffException1 extends Exception{}
  12. class OnOffException2 extends Exception{}
  13. public class OnOffSwitch {
  14. static Switch sw = new Switch();
  15. public static void f() throws OnOffException1,OnOffException2{}
  16. public static void main(String[] args) {
  17. try {
  18. sw.on();
  19. f();
  20. //sw.off(); //注掉发现并没有执行下列catch中任何一个off方法
  21. }catch (OnOffException1 e){
  22. System.out.println("OneException1");
  23. sw.off();
  24. }catch (OnOffException2 e){
  25. System.out.println("OneException2");
  26. sw.off();
  27. }
  28. }
  29. }

此时finally的作用就来了

  1. public class OnOffSwitch {
  2. static Switch sw = new Switch();
  3. public static void f() throws OnOffException1,OnOffException2{}
  4. public static void main(String[] args) {
  5. try {
  6. sw.on();
  7. f();
  8. //sw.off();
  9. }catch (OnOffException1 e){
  10. System.out.println("OneException1");
  11. sw.off();
  12. }catch (OnOffException2 e){
  13. System.out.println("OneException2");
  14. sw.off();
  15. }finally { //finally子句总可以运行
  16. sw.off();
  17. }
  18. }
  19. }

甚至异常没有被当前的异常处理程序捕获的情况下,异常处理机制,也会在跳在更高一层的异常处理程序之前,执行finally子句

  1. class FourException extends Exception{}
  2. public class AlwaysFinally {
  3. public static void main(String[] args) {
  4. System.out.println("first");
  5. try {
  6. System.out.println("second");
  7. try {
  8. throw new FourException();
  9. }finally {
  10. System.out.println("2nd");
  11. }
  12. }catch (Exception e){
  13. System.out.println("3rd");
  14. }finally {
  15. System.out.println("4th");
  16. }
  17. }
  18. }

在return中使用finally

  1. public class MultipleReturns {
  2. public static void f(int i){
  3. System.out.println("=====================");
  4. try {
  5. System.out.println("1");
  6. if (i == 1){return;};
  7. System.out.println("2");
  8. if (i == 2){return;}
  9. System.out.println("3");
  10. if (i == 3){return;}
  11. }finally {
  12. System.out.println("Always finally");
  13. }
  14. }
  15. public static void main(String[] args) {
  16. for (int i = 1; i < 4; i++) {
  17. f(i);
  18. }
  19. }
  20. }

执行finally语句之后才会return

缺憾: 异常丢失

  1. class VeryImportantException extends Exception{
  2. @Override
  3. public String toString() {
  4. return " A very important exception";
  5. }
  6. }
  7. class HomuException extends Exception{
  8. @Override
  9. public String toString() {
  10. return "A trivial exception";
  11. }
  12. }
  13. public class LostMessage {
  14. void f() throws VeryImportantException {
  15. throw new VeryImportantException();
  16. }
  17. void g() throws HomuException {
  18. throw new HomuException();
  19. }
  20. public static void main(String[] args) {
  21. try {
  22. LostMessage lm = new LostMessage();
  23. try {
  24. lm.f();
  25. }finally {
  26. lm.g();
  27. }
  28. }catch (Exception e){
  29. System.out.println(e); //VeryImportantException丢失了
  30. }
  31. }
  32. }