异常中的陷阱

正确关闭资源的方式

①使用finally块来关闭物理资源。

②关闭物理资源时,首先保证引用资源的变量不为null

③每个物理资源时都应该使用单独的try-catch块来关闭资源,保证关闭资源时引发的异常不会影响其他资源的关闭。

finally的陷阱

System.exit(0);

在try中使用了System.exit(0);语句,将停止当前线程和所有其他当场死亡的线程。catch和finally块都不会被执行。因为线程都立即死亡了,怎么会执行下面的东西呢?

那么当出现System.exit(0);语句后,我们怎么来清理物理资源呢?

→将关闭资源的操作注册为关闭钩子。(JVM在退出之前,这些关闭钩子会被调用,从而保证物理资源被正常关闭)。

public class test {
    public  static void main(String[] args) throws Exception {
        final FileOutputStream fos;
        fos=new FileOutputStream("D:\\a.bin");
        System.out.println("程序打开物理资源");
        //为系统注册关闭钩子
        Runtime.getRuntime().addShutdownHook(new Thread(){
            public void run(){
                //使用关闭钩子来关闭资源
                if(fos!=null){
                    try {
                        fos.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("程序关闭了物理资源");
            }
        });
        //退出程序
        System.exit(0);
    }
}

finally块和try中的return、throw

public class test {
    public  static void main(String[] args) throws Exception {
        int a=test1();
        System.out.println(a);
    }
    public static int test1(){
        int count=5;
        try {
            return count+=5;
        } catch (Exception e) {
            // TODO: handle exception
        }finally{
            System.out.println("finally块被执行");
            return count+=10;
        }
    }
}

打印结果为:

我们来看看反编译后的代码:


public class test {
  public static void main(String[] args) throws Exception {
    int a = test1();
    System.out.println(a);
  }

  public static int test1() { int count = 5;
    try {
      count += 5;
    }
    catch (Exception localException) {}finally
    {
      System.out.println("finally块被执行"); }
    count += 10;return count;
  }
}

为什么没有放在finally块中呢?因为,从代码块看,count+=2;处于前一个return和后一个return之后,即,当前一个return不起作用的情况下才会执行这个语句。前一个return不起作用的情况只有try中出现了异常,所以count+=2放到了catch块中,而finally块每次都会被执行,放在这里没有任何意义。

因为finally总会被执行,而这里函数已经返回,绝对不会再放后面执行了,所以count是不可达的。出现编译错误。

如果有finally语句,则try中的return 语句会把要返回的值先保存了一份,然后去执行finally语句,finally语句执行完毕之后再返回之前try语句块中保存的那个值,如果try中return的是基本类型的,finally里对变量的改动将不起效果,如果return的是引用类型的,那改动了对象中的值就可以起效果。

try中的return被短路了。

当程序执行try块、catch块时,遇到throw语句时,throw语句会导致该方法立即结束,系统执行throw语句并不会立即抛出异常,而是去寻找该异常处理流程中是否包含finally块。如果没有finally块,程序立即抛出异常;如果有finally块,系统立即开始执行finally块,只有当finally块执行完后,系统才会再次跳回来抛出异常。如果finally块中使用了return语句来结束方法,系统不会跳回去执行try块、catch块去抛出异常。

只能catch try中可能抛出的异常

try中有可能抛出什么异常,后面的catch中才能捕获什么异常,否则会出现编译错误。但是Exception是个例外,即无论try块是什么代码,catch(Exception e)总是正确的。

RuntimeException类及其子类的实例被称为Runtime异常,不是RuntimeException类的及其子类的异常实例被称为Checked异常,如:

只要愿意,程序总可以使用catch(XxxException ex)来捕获运行时异常,它比较灵活,无需显示声明抛出,只要程序需要,即可在任何又需要的地方使用try...catch块来捕获runtime异常。但是catch如果捕获一个Checked异常,那么该catch对象的try必须能抛出该类或其子类的异常。

本文链接:http://www.cnblogs.com/yaoyinglong/p/Java%E5%BC%82%E5%B8%B8%E4%B8%AD%E7%9A%84%E9%99%B7%E9%98%B1.html

时间: 2024-08-25 13:45:16

异常中的陷阱的相关文章

java —— 异常中的陷阱(四)

一.使用 finally 正确关闭资源的方式 finally 块无论程序是否异常总是会被执行,因此常用来关闭物理资源,从而保证资源总能被关闭. import java.io.*; public class CloseResource { //一个函数同时读取两个文件 public void readTwoFile() throws FileNotFoundException, IOException{ BufferedReader br1 = null; BufferedReader br2 =

进程—异常控制流之陷阱篇

一.Exceptions(异常) and System Call(系统调用) 1.1 陷阱 陷阱是有意为之的异常,是处理器执行程序的一条指令的结果.陷阱最重要的用途是提供用户程序和内核之间一个像普通过程调用似的接口,名曰:系统调用.用户程序经常需要向内核请求服务,比如读一个文件(read) .创建一个新的进程(fork) .加载一个新的程序(execv),或者终止当前进程(exit) .为了允许对这些内核服务的受控的访问,处理器提供了一条特殊的 "syscall n" 指令,当用户程序

S5PV210-arm裸机-异常中的中断实现过程

210中的异常中的中断实现过程: 首先异常分为很多种,异常中包含了中断异常,有一个东西叫做异常向量表,在异常向量表中有很多相应异常的的地址.异常向量表中的所有异常中断的地址是不会变化的.地址都是固定的,但这些地址都是一个基于基地址的一个地址.不同的CPU中,基地址是不同的. 在210中,CPU内部给了一个发生异常时的异常向量的基地址,查阅官方资料知道,这个基地址为0XD0037400,所以我们需要自己把异常向量表中的地址加在210给的发生异常时的异常向量的基地址上.比如:reset(复位异常)在

【JavaScript】JavaScript中的陷阱大集合

本文主要介绍怪异的Javascript,毋庸置疑,它绝对有怪异的一面.当软件开发者开始使用世界上使用最广泛的语言编写代码时,他们会在这个过 程中发现很多有趣的“特性”.即便是老练的Javascript开发者也可以在本文找到一些有趣的新陷阱,请留意这些陷阱,当然也可以尽情享受由这些陷阱 带来的“乐趣”! AD: 本文主要介绍怪异的Javascript,毋庸置疑,它绝对有怪异的一面.当软件开发者开始使用世界上使用最广泛的语言编写代码时,他们会在这个过 程中发现很多有趣的“特性”.即便是老练的Java

编写高质量代码改善C#程序的157个建议——建议38:小心闭包中的陷阱

建议38:小心闭包中的陷阱 先看一下下面的代码,设想一下输出的是什么? static void Main(string[] args) { List<Action> lists = new List<Action>(); for (int i = 0; i < 5; i++) { Action t = () => { Console.WriteLine(i.ToString()); }; lists.Add(t); } foreach (Action t in list

异常中的特殊情况--RuntimeException类

如果在函数内容抛出该异常,函数上可以不用声明,调用者可以不用进行处理,编译一样通过(当然,也可以声明和处理). 之所以不用在函数声明,是因为不需要让调用者进行处理. 当该异常发生时,希望程序停止.因为在运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修正. 自定义异常时,如果该异常的发生,无法再继续进行运算, 就让自定义异常继承RuntimeException. 对于异常分两种: 1,在编译时被检测的异常. 函数内容抛,函数上抛,调用者要么抛 要么捕获. 2,编译时不被检测到的异常(

编写高质量代码改善C#程序的157个建议——建议83:小心Parallel中的陷阱

建议83:小心Parallel中的陷阱 Parallel的For和ForEach方法还支持一些相对复杂的应用.在这些应用中,它允许我们在每个任务启动时执行一些初始化操作,在每个任务结束后,又执行一些后续工作,同时,还允许我们监视任务的状态.但是,记住上面这句话“允许我们监视任务的状态”是错误的:应该把其中的“任务”改成“线程”.这,就是陷阱所在. 我们需要深刻理解这些具体的操作和应用,不然,极有可能陷入这个陷阱中去.下面体会这段代码的输出是什么,如下所示: static void Main(st

编写高质量代码改善C#程序的157个建议——建议68:从System.Exception或其他常见的基本异常中派生异常

建议68:从System.Exception或其他常见的基本异常中派生异常 微软建议:从System.Exception或其他常见基本异常之一派生异常.在Visual Studio中输入Exception,然后按快捷键Tab,VS会自动创建一个自定义异常类: [Serializable] public class MyException : Exception { // // For guidelines regarding the creation of new exception types

如何避开协同oa选型中不为人知的陷阱?

在移动互联网高速发展的信息化时代,企业想要提高运转效率,必然需要利用这一优势,来实现办公的自动化.如此,协同oa则是全员信息化的第一步,能够帮助企业规范信息化的建设. 而很多中小型企业在选择协同oa的时候总会陷入"选择困难症"的泥沼当中,因为市面上有太多的移动协同oa,从而陷入了进退两难的境地. 那么如何避开协同oa选型中不为人知的陷阱?从而摆脱不必要的后患. 1.避开遥遥无期的实施周期 如果希望为企业量身定制协同oa,就要避开复杂的功能.因为很多协同oa功能强大而繁琐,就会导致实施困