java中try-catch-finally异常处理例子

这一小节概述了try-catch-finally 语句是怎样处理错误的,文中的例子是Java的,但是同样的规则也适用于C#。java和C#中异常的唯一区别就是C#中没有已检查异常。已检查异常和未检查异常将在后面小节更加详细地介绍。

程序中的异常表明一些错误或者异常情况发生了,异常如果没有被处理,继续程序流程是没有意义的。一个方法可能会因为各种原因抛出异常,比如输入参数是无效的(当期待获得正数时输入了负数等。)

调用栈
下面介绍调用栈。调用栈是指从当前的方法开始一直到main方法处的方法调用序列。如果方法A调用方法B,方法B调用方法C,则调用栈如下所示:

    A
    B
    C
当方法C返回后,调用栈仅仅包含A和B,如果方法B再调用方法D,则调用栈如下所示:

    A
    B
    D
理解调用栈对理解异常传播是非常重要的。从抛出异常的方法开始,异常根据调用栈传播,直到调用栈中某个方法捕获该异常。更多细节稍后讨论。

抛出异常
如果一个方法要抛出异常,那么要在方法签名中声明这个异常,然后在方法里包含一条throw语句。下面是一个例子:

    public void divide(int numberToDivide, int numberToDivideBy)
    throws BadNumberException{
        if(numberToDivideBy == 0){
            throw new BadNumberException("Cannot divide by 0");
        }
        return numberToDivide / numberToDivideBy;
    }
当一个异常被抛出时,方法在抛出异常处停止运行。throw语句后的任何语句都将不会被执行了。在上面这个例子中,如果抛出BadNumberException异常,那么”return numberToDivide / numberToDivideBy;”这条语句将不会被执行。当异常被catch语句块捕获时,程序才会继续执行。捕获异常稍后解释。

只要在方法签名中做了声明,你可以抛出任何异常。你也可以创建自己的异常。异常是继承自java.lang.Exception的标准java类或者任何其他的内置异常类。如果一个方法声明抛出异常A,那么方法抛出异常A的子类异常也是合法的。

捕获异常
如果一个方法调用了另一个会抛出已检查异常的方法,那么这个调用方法必须要么传递这个异常,要么捕获这个异常。捕获异常是利用try-catch语句块来实现的。下面是一个例子:

    public void callDivide(){
        try {
            int result = divide(2,1);
            System.out.println(result);
        } catch (BadNumberException e) {
            //do something clever with the exception
            System.out.println(e.getMessage());
        }
        System.out.println("Division attempt done");
    }
当抛出异常时,catch语句中的BadNumberException 类型参数e就代表从divide方法中抛出的异常。

如果try语句块中任何被调用的方法和执行的语句都没有抛出异常,catch语句块仅仅被忽略,不会被执行。

如果try语句块中抛出异常,例如在divide方法中抛出异常,调用方法(即callDrive方法)中的程序流将会像divide方法中的程序流一样被中断。程序流将在调用栈中某个能够捕获这个异常的catch语句块处恢复。上面例子中,如果一个异常从divide方法中抛出,那么“System.out.println(result);” 语句将不会被执行。这时程序将会在catch (BadNumberException e) { }语句块里恢复执行。

如果在ctach语句块里抛出了一个没有被捕获的异常,那么catch语句块的运行将会像try语句中块抛出异常一样被中断。

当catch语句块执行完,程序将会执行catch语句块后面的所有语句。上面例子中的”System.out.println(“Division attempt done”);” 语句将永远会被执行。

异常传播
你也没有必要捕获其他方法中抛出的异常。如果你在方法抛出异常的地方不能对异常做任何事,你可以让方法根据调用栈将这个异常传播到调用这个方法的其他方法处。如果你这样做,调用这个将抛出异常方法的其他方法必须要在方法签名中声明抛出这个异常。下面是callDivide()方法在这种情况下的例子:

public void callDivide() throws BadNumberException{
       int result = divide(2,1);
       System.out.println(result);
}
注意try-catch语句块不见了,callDivide 方法声明它会抛出一个BadNumberException异常。如果divide方法里抛出一个异常,程序仍将被中断。因此如果divide方法里抛出一个异常,”System.out.println(result);” 语句将不会被执行。但是这样的话callDivide 方法中(因为抛出异常而中断的的)程序执行不会被恢复。异常会被传播到调用callDivide的方法中。直到调用栈中的某个catch语句块捕获了这个异常,程序执行才会恢复。根据调用栈,从抛出异常的方法到捕获异常的方法之间的所有方法的运行都将停止在异常抛出或者传播的代码处。

捕获IOException示例
如果一个异常在try语句块中被抛出,程序的顺序执行将会被中断,控制流将直接跳转到catch语句块。代码将会因为异常在几个地方被中断:

public void openFile(){
        try {
            // constructor may throw FileNotFoundException
            FileReader reader = new FileReader("someFile");
            int i=0;
            while(i != -1){
                //reader.read() may throw IOException
                i = reader.read();
                System.out.println((char) i );
            }
            reader.close();
            System.out.println("--- File End ---");
        } catch (FileNotFoundException e) {
            //do something clever with the exception
        } catch (IOException e) {
            //do something clever with the exception
        }
    }
如果reader.read()方法调用抛出一个IO异常,下面的System.out.println((char) i );语句不会被执行。最后的reader.close() 和System.out.println(“— File End —“);语句也不会被执行。程序直接调转到catch(IOException e){ … }语句块处。如果new FileReader(“someFile”); 构造器中调用抛出一个异常,那么try语句块中的代码都不会被执行了。

传播IOException示例
下面的代码仍然以上面的方法为例,不过这里没有捕获异常:

public void openFile() throws IOException {
        FileReader reader = new FileReader("someFile");
        int i=0;
        while(i != -1){
            i = reader.read();
            System.out.println((char) i );
        }
        reader.close();
        System.out.println("--- File End ---");
    }
如果reader.read()  方法抛出一个异常,程序将会停止运行,异常根据调用栈传播到调用openFile()方法的方法处。如果这个调用方法有try-catch语句块,异常将在这里被捕获。如果这个调用方法也只是抛出异常,这个调用方法的运行将在调用openFile()方法处中断,异常根据调用栈往外传播。异常就是这样根据调用栈往外传播,直到某个方法或者java虚拟机捕获了这个异常。

Finally
你也可以在try-catch语句块后增加一个finally语句块。不论try还是catch语句块中抛出异常,finally语句块中的代码将永远执行。如果代码里的try或者catch语句块中有个return语句,finally语句块中的代码将会在方法返回之前执行。finally示例见下:

public void openFile(){
        FileReader reader = null;
        try {
            reader = new FileReader("someFile");
            int i=0;
            while(i != -1){
                i = reader.read();
                System.out.println((char) i );
            }
        } catch (IOException e) {
            //do something clever with the exception
        } finally {
            if(reader != null){
                try {
                    reader.close();
                } catch (IOException e) {
                    //do something clever with the exception
                }
            }
            System.out.println("--- File End ---");
        }
    }
不论try或者catch语句块中是否有异常抛出,finally语句块中的代码都将被执行。这个例子表明不论try、catch语句块中的程序运行情况如何,文件读取始终会被关闭。

注意:如果finally语句块中抛出一个异常,并且没有被捕获,finally语句块就像try、catch语句块抛出异常一样也会被中断运行。这就是为什么上面的例子中finally语句块中的reader.close() 方法也被try-catch语句块包裹原因:

} finally {
            if(reader != null){
                try {
                    reader.close();
                } catch (IOException e) {
                    //do something clever with the exception
                }
            }
            System.out.println("--- File End ---");
        }
通过这样,System.out.println(“— File End —“);语句将会永远被执行。更准确地说是没有未检查异常被抛出时是这样。更多关于已检查异常和未检测异常的知识将在后面章节介绍。

你的程序中不需要同时又catch、finally语句块。try语句块后可以仅仅有catch语句块或者finally语句块,但是try语句块后既没有catch语句块也没有finally语句块是不行的。下面的代码不会捕获异常而是让异常根据调用栈往外传播,但是由于finally语句块的存在,即是有异常抛出,程序仍旧能关闭打开的文件。

public void openFile() throws IOException {
        FileReader reader = null;
        try {
            reader = new FileReader("someFile");
            int i=0;
            while(i != -1){
                i = reader.read();
                System.out.println((char) i );
            }
        } finally {
            if(reader != null){
                try {
                    reader.close();
                } catch (IOException e) {
                    //do something clever with the exception
                }
            }
            System.out.println("--- File End ---");
        }
    }
注意上面catch语句块不见了。

捕获异常还是传播异常?
你可能疑问:程序中抛出的异常是应该捕获还是让其传播?这取决于具体情况。在许多应用程序中,除了告诉用户请求操作失败,你不能对异常做其他更多事情。在这种情况下,你可以在调用栈中的第一个方法里捕获所有的、或者大多数的异常。在传播异常时,你仍然可以处理异常(通过finally语句)。比如,在一个web应用程序中的数据库连接出现了错误,即使你所能做的只是告诉用户这个操作失败,你仍然应该在finally语句中关闭这个数据库连接。最终如何处理异常也取决于你的程序中抛出的是已检查异常还是未检查异常。关于已检查异常、未检查异常,后面将有更多文章介绍。

时间: 2025-01-31 05:51:49

java中try-catch-finally异常处理例子的相关文章

java android-关于java中try catch的问题

问题描述 关于java中try catch的问题 try{}catch(Exception){} 有无可能try中的代码 和catch中的代码都没有执行到.小弟最近做个项目程序中try { ImageModel result = future.get(10, TimeUnit.SECONDS); LogModel entity = new LogModel(); entity.setLog(result.getMs() + result.getStatus()); entity.setCarId

PL/SQL实现JAVA中的split()方法的例子_java

众所周知,java中为String类提供了split()字符串分割的方法,所以很容易将字符串以指定的符号分割为一个字符串数组.但是在pl/sql中并没有提供像java中的split()方法,所以要想在pl/sql中实现字符串的分割还需要自己动手.由于在项目中需要用到此类方法,所以自己研究了一下,方便以后参考.这里以逗号作为分隔符为例,代码如下: declare v_str varchar2(200) := 'abd,324,u78,23f,sd09,2345,dsaf,9079'; type s

剖析Java中的事件处理与异常处理机制_java

一.事件处理其实,由事件处理这个名字自然就想到MFC中的消息响应机制,就我的体会,它们应该算是南桔北枳的情形吧,我怀疑Java中的事件处理这个"新瓶"应是装的MFC中的消息响应这个"旧酒".     所谓的"事件"即如键盘按键.鼠标点击等这类由动作或什么导致某个状态改变并需要对这个改变作相应响应的这类改变.我们可以将Java中的事件分为按钮.鼠标.键盘.窗口.其它事件这几大类.    事件处理模型  1.   基于继承的事件处理模型(JDK1.0

php中try catch 捕获异常的例子

pHP中try{}catch{}语句 PHP 5 添加了类似于其它语言的异常处理模块.在 PHP 代码中所产生的异常可被 throw语句抛出并被 catch 语句捕获.(注:一定要先抛才能获取) 需要进行异常处理的代码都必须放入 try 代码块内,以便捕获可能存在的异常. 每一个 try 至少要有一个与之对应的 catch. 使用多个 catch可以捕获不同的类所产生的异常. 当 try 代码块不再抛出异常或者找不到 catch 能匹配所抛出的异常时,PHP 代码就会在跳转到最后一个 catch

分享JavaScript与Java中MD5使用两个例子_javascript技巧

在网上查了一下,在网上收集了Java与JavaScript中使用的两个例子,试验过,分享下.1.Java: package org.bearfly.test.md5; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5Utils { public static

java中的hashCode方法小例子_java

在java中,有一个这样的规定,就是两个相同的对象(即equals运算为true),它们的hash code也必须相同.在Object类中有一个hashCode方法,可以调用它来查看对象的hash code.下面举例说明. 复制代码 代码如下: package test; public class Test {  public static void main(String args[]){  String str1 = "aaa";  String str2 = str1;  Str

java中Spark 构建轻量级服务例子

来看下一个最简单的例子 1 . 在pom.xml中增加      <dependency>             <groupId>com.sparkjava</groupId>             <artifactId>spark-core</artifactId>             <version>2.0.0</version>      </dependency> 2 . 新建一个Clas

java中属性文件读取的例子

  import java.io.InputStream;import java.util.Properties;   public class ConfigUtil{  private static Properties prop=new Properties();  private static boolean isLoaded=false;  public ConfigUtil()  {  }  public static Properties getConfigInfo()  {   

java中string转bigdecimal的例子

例子1,string 转BigDecimal public class Test{     public static void main(String[] arg) {         String str1="2.30";         BigDecimal bd=new BigDecimal(str1);         System.out.println(bd);     } } 直接new  就行了. 例子2,BigDecimal和String的相互转换 /*由数字字符串

java-Java中try....catch语句除了可以捕获异常并输出异常信息,还有什么用呢

问题描述 Java中try....catch语句除了可以捕获异常并输出异常信息,还有什么用呢 Java中try....catch语句除了可以捕获异常并输出异常信息,还有什么用呢 解决方案 catch语句中不仅可以输出异常,也可以对异常进行处理,比如,从控制台输入数字,发生数字格式异常后,在catch语句中可以给出提出信息,要求重新输入 解决方案二: Java异常捕获之try...catch...finally语句try~Catch语句中异常的处理过程JAVA 异常 try-catch 解决方案三