zoukankan      html  css  js  c++  java
  • [Java解惑]异常

     

    异常... 17
    26.      finally与中断... 17
    27.      catch捕获异常规则... 18
    28.      重写时方法异常范围... 19
    29.      静态与非静态final常量不能在catch块中初始化... 19
    30.      System.exit()finally. 20
    31.      递归构造... 21
    32.      构造器中的异常... 21
    33.      StackOverflowError22

    异常

    26.finally与中断


    //该方法返回false
    static boolean f() {
           try {
                  return true;
           } finally {
                  return false;
           }
    }
     
    不要用returnbreakcontinuethrow来退出finally语句块,并且千万不要允许受检查的异常传播到finally语句块之外。也就是说不要在finally块内终止程序,而是执行完finally块后,要将控制权移交给try块,由try最终决定怎样结束方法的调用。
     
    对于任何在finally语句块中可能抛出的受检查异常都要进行处理,而不是任其传播,下面流拷贝程序在关闭流时没有防止异常的传播,这会有问题:
    static void copy(String src, String dest) throws IOException {
           InputStream in = null;
           OutputStream out = null;
           try {
                  in = new FileInputStream(src);
                  out = new FileOutputStream(dest);
                  byte[] buf = new byte[1024];
                  int n;
                  while ((n = in.read(buf)) >= 0) {
                         out.write(buf, 0, n);
                  }
           } finally{
                  //这里应该使用try-catch将每个close包装起来
                  if(in != null){in.close();}
                  if(in != null){out.close();}
           }
    }
     
    catch块中的return语句是不会阻止finally块执行的,那么catch块中的continuebreak能否阻止?答案是不会的,与return一样,finally语句块是在循环被跳过(continue)和中断(break)之前被执行的:
    int i = 0;
    System.out.println("--continue--");
    while (i++ <= 1) {
           try {
                  System.out.println("i=" + i);
                  continue;
           } catch (Exception e) {
           } finally {
                  System.out.println("finally");
           }
    }
    System.out.println("--break--");
    while (i++ <= 3) {
           try {
                  System.out.println("i=" + i);
                  break;
           } catch (Exception e) {
           } finally {
                  System.out.println("finally");
           }
    }

    27.catch捕获异常规则


    捕获RuntimeExceptionExceptionThrowablecatch语句是合法,不管try块里是否抛出了这三个异常。但如果try块没有抛出或不可能抛出检测性异常,则catch不能捕获这些异常,如IOException异常:
    public class Test {
           public static void main(String[] args) {
                  try{
                         //...
                  }catch (Exception e) {
                        
                  }catch (Throwable e) {
                        
                  }
                 
                  /* !! 编译出错
                         try{
                                //...
                         }catch (IOException e) {
                               
                         }
                   */
           }
    }

    28.重写时方法异常范围


    重写或实现时不能扩大异常的范围,如果是多继承,则异常取所有父类方法异常的交集或不抛出异常:
    interface I1 {
           void f() throws Exception;
    }
     
    interface I2 {
           void f() throws IOException;
    }
     
    interface I3 extends I1, I2 {}
     
    class Imp implements I3 {
           // 不能编译通过,多继承时只能取父类方法异常交集,这样就不会扩大异常范围
           // !! void f () throws Exception;
           // void f();// 能编译通过
           // 能编译通过,ExceptionIOException的交集为IOException
           public void f() throws IOException {
           }
    }

    29.静态与非静态final常量不能在catch块中初始化


    静态与非静态块中如果抛出了异常,则一定要使用try-catch块来捕获。
     
    public class Test {
           static final int i;
           static {
                  try {
                         i = f();
                  } catch (RuntimeException e) {
                         i = 1;
                  }
           }
     
           static int f() {
                  throw new RuntimeException();
           }
    }
    上面的程序编译不能通过。表面上是可以的,因为i第一次初始化时可能抛出异常,所以抛异常时可以在catch块中初始化,最终还是只初始化一次,这正是空final所要求的,但为什么编译器不知道这些呢?
     
    要确定一个程序是否不止一次地对一个空final进行赋值是很困难的问题。语言规范在这一点上采用了保守的方式。

    30.System.exit()finally


    try {
           System.out.println("Hello world");
           System.exit(0);
           // 或者使用Runtime退出系统
           // Runtime.getRuntime().exit(0);
    } finally {
           System.out.println("Goodbyte world");
    }
    上面的程序会打印出"Goodbyte world"吗?不会。
     
    System.exit将立即停止所有的程序线程,它并不会使finally语句块得到调用,但是它在停止VM之前会执行关闭挂钩操作(这此挂钩操作是注册到Runtime.addShutdownHook上的线程),这对于释放VM之外的资源很有帮助。使用挂钩程序修改上面程序:
    System.out.println("Hello world");
    Runtime.getRuntime().addShutdownHook(new Thread() {
           public void run() {
                  System.out.println("Goodbyte world");
           }
    });
    System.exit(0);
     
    对象回收时,使用VM调用对象的finalize()方法有两种:
    System.runFinalization():该方法让虚拟机也只是尽最大努力去完成所有未执行的finalize()终止方法,但不一定会执行。
    System.runFinalizersOnExit(true):该方法一定会回收,但不安全,已被废弃。因为它可能对正在使用的对象调用终结方法,而其他线程同时正在操作这些对象,从而导致不正确的行为或死锁。
     
    为了加快垃圾回收,使用System.gc(),但不一定马上执行加收动作,由虚拟机决定,实质上是调用Runtime.getRuntime().gc()
     
    System的很多方法都是调用Runtime类的相关方法来实现的。

    31.递归构造


    public class S  {
           private S instance = new S();
           public S() {}
    }
     
    如果在程序外面构造该类的实例,则会抛出java.lang.StackOverflowError错误。其原因是实例变量的初始化操作将先于构造器的程序体而运行。

    32.构造器中的异常


    如果父类构造器抛出了检测异常,则子类也只能抛出,而不能采用try-catch来捕获:
    public class P {
           public P() throws Exception {}
    }
     
    class S extends P {
           public S() throws Exception {
                  try {
                         // 不能在try块中明确调用父类构造器,因为构造的
                         // 明确调用只能放在第一行
                         // !! super();
                  //try-catch不能捕获到父类构造器所抛出的异常,子类只能抛出
                  } catch (Exception e) {
                  }
           }
    }
     
     
    如果初使化实例属性时抛出了异常,则构造器只能抛出异常,在构造器中捕获不起作用:
    public class A  {
           private String str = String.class.newInstance();
           public A()throws InstantiationException, IllegalAccessException {}
           public A(int i) throws Exception{
                  try {
                        
                  } catch (Exception e) {
                        
                  }
           }
    }
     

    33.StackOverflowError


    Java虚拟机对栈的深度限制到了某个值,当超过这个值时,VM就抛出StackOverflowError。一般VM都将栈的深度限制为1024,即当方法调用方法的层次超过1024时就会产生StackOverflowError

  • 相关阅读:
    基于Java的地铁线路查询系统设计思路
    个人总结05
    构建之法读书笔记03
    Java 8 (二) 新的时间API
    MySql基础笔记(三)其他重要的事情
    MySql基础笔记(二)Mysql语句优化---索引
    JavaScript基础笔记(十四)最佳实践
    JavaScript基础笔记(十三)测试和调试
    MySql基础笔记(一)Mysql快速入门
    JavaScript基础笔记(十二)Ajax
  • 原文地址:https://www.cnblogs.com/jiangzhengjun/p/4257578.html
Copyright © 2011-2022 走看看