3
import java.io.*;
class ex3
{

    public static void main(String args[])
    {
       myfun();
    }

    static void myfun()
    {
        try
        {
           FileInputStream f = new FileInputStream("file.ytxt");
           System.out.println("my fun");
        }

        catch(Exception e) //Line 1
        {
           System.out.println(e.getMessage());
        }

        catch(FileNotFoundException e) //Line 2
        {
           System.out.println("File Not Found Caught");
        }
    }
}

我创建了两个异常处理程序代码(一个是通用的,另一个是第 1 行和第 2 行中的特定代码)。

我的编译器在抱怨

ex3.java:24: error: exception FileNotFoundException has already been caught
                catch(FileNotFoundException e)
                ^
1 error

我的问题是编译器怎么知道 try 块会抛出“FileNotFoundException”?

4

10 回答 10

10

catch(FileNotFoundException e)这条线是无法到达的。自从:

FileNotFoundException extends Exception

请参阅异常FileNotFoundException

在此处输入图像描述

你可能想改变他们的顺序。

于 2013-08-21T13:27:42.900 回答
6

你的问题出在其他地方。FileNotFoundException将始终被捕获,Exception因为这是所有异常的基类。所以编译器基本上会抱怨一段死代码

catch(FileNotFoundException e) {
    System.out.println("File Not Found Caught");
}

一般来说,catch 不是一个好主意Exception,你应该总是尝试有更细粒度的异常处理,所以删除它并留下FileNotFoundException

于 2013-08-21T13:28:31.767 回答
4

你的编译器可以看到这个异常已经被前面的 catch 块捕获了。

当你 catchException时,它还会捕获 Exception 的任何子类,例如FileNotFoundException.

将 catch 块的顺序交换为:

    catch(FileNotFoundException e) //Line 2
    {
        System.out.println("File Not Found Caught");
    }
    catch(Exception e) //Line 1
    {
        System.out.println(e.getMessage());
    }
于 2013-08-21T13:27:33.177 回答
2

回答

我的问题是编译器怎么知道 try 块会抛出“FileNotFoundException”?

您需要查看构造函数FileInputStream

public FileInputStream(String name) throws FileNotFoundException {
    this(name != null ? new File(name) : null);
}

注意它throws FileNotFoundException。这个声明告诉编译器 aFileNotFoundException可能被抛出,所以确保用一个try-catch块来处理它,或者让它在方法堆栈上用另一个throws子句冒泡。

至于您遇到的错误,请查看所有其他答案。

于 2013-08-21T13:32:58.490 回答
2

这里有几件事在起作用。

首先,编译器知道 aFileNotFoundException可以被抛出,因为FileInputStream构造函数的方法签名。从文档

public FileInputStream(String name) throws FileNotFoundException

因此,签名告诉编译器它可以抛出FileNotFoundException.

但是,在这种情况下,由于块的顺序,这些信息实际上并不重要catch。你有:

catch(Exception e) { /* ... */ }
catch(FileNotFoundException e) { /* ... */ }

块的工作方式catch,如果在块中抛出异常try,执行将遍历每个cacth块并查看catch块中的异常类型是否与所抛出异常的多态匹配。由于是从(见这里FileNotFoundException)的后代,它匹配第一个块并且总是匹配。因此,第二个块是不可达的。Exception

因此,即使编译器知道 aFileNotFoundException可以被抛出,它仍然可以推断出第二个catch块是不可达的,因为任何FileNotFoundException抛出的块总是会被第一个块捕获。

定义catch块时,始终按照最具体到最不具体的顺序排列它们,以避免这个问题。

于 2013-08-21T13:35:41.657 回答
1

改变这个 -

    catch(Exception e) //Line 1
    {
        System.out.println(e.getMessage());
    }

    catch(FileNotFoundException e) //Line 2
    {
        System.out.println("File Not Found Caught");
    }

对此——

    catch(FileNotFoundException e) //Line 1
    {
        System.out.println(e.getMessage());
    }
    catch(Exception e) //Line 2
    {
        System.out.println("File Not Found Caught");
    }

Exception是Java中所有异常类的超类型。因此,任何异常对象都可以分配给 type 的引用Exception。当程序中发生异常时,会从上到下依次检查 catch 块,以查找发生的异常类型与catch块正在处理的异常类型之间的匹配项。因此,在您的 try 块中生成的任何类型的异常总是会找到第一个 catch 块作为匹配项,而您的代码永远无法到达第二个 catch 块。这正是编译器抱怨的原因。

于 2013-08-21T13:29:09.463 回答
1
catch(Exception e) 
    {
       System.out.println(e.getMessage());
    }

    catch(FileNotFoundException e) 
    {
       System.out.println("File Not Found Caught");
    }

异常是所有异常的超类。

因此,如果我们使用 catch(Exception e){} 那么它可以捕获所有类型的异常。

所以 catch(FileNotFoundExecption f){} 将无法访问,因此编译器会给出一个错误,它已经被捕获。

这是正确的写法:

    catch(FileNotFoundException e) 
    {
       System.out.println("File Not Found Caught");
    }
    catch(Exception e) 
    {
       System.out.println(e.getMessage());
    }
于 2013-08-21T14:55:10.670 回答
0

这不是重点:catch(Exception e)会捕获任何Exceptionie FileNotFoundException。因此,第二次捕捉FileNotFoundException是没有用的。

先抓FileNotFoundException,再抓Exception

于 2013-08-21T13:29:14.410 回答
0

catch 块将拦截指定类及其所有子类的异常。正如其他提到FileNotFoundException的是一个子类,Exception因此它将被

catch (Exception e)

条款。

于 2013-08-21T13:32:21.700 回答
0

Java 虚拟机规范:异常

Java 虚拟机中的每个方法都可能与零个或多个异常处理程序相关联。异常处理程序指定在 Java 虚拟机代码中实现异常处理程序处于活动状态的方法的偏移范围,描述异常处理程序能够处理的异常类型,并指定要处理的代码的位置那个例外。如果导致异常的指令的偏移量在异常处理程序的偏移范围内,并且异常类型与异常处理程序处理的异常类的类或子类相同,则异常匹配异常处理程序。当抛出异常时,Java 虚拟机在当前方法中搜索匹配的异常处理程序。如果找到匹配的异常处理程序,

搜索方法的异常处理程序以查找匹配项的顺序很重要。在类文件中,每个方法的异常处理程序都存储在一个表中(第 4.7.3 节)。在运行时,当抛出异常时,Java 虚拟机按照它们出现在类文件中相应异常处理程序表中的顺序从该表的开头开始搜索当前方法的异常处理程序。

如果 JDK 编译这样的代码 FileNotFoundException 块将无法访问。由于检查了异常对象instanceof,它总是会落入第一个异常块中。对于您的情况,正确的表格将是:

  Exception table:
   from   to  target type
     0    18    21   Class java/io/FileNotFoundException
     0    18    33   Class java/lang/Exception

其中fromto是指令编号。该表是自上而下搜索的。

于 2013-08-21T18:40:41.950 回答