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”的?
答案 0 :(得分:10)
catch(FileNotFoundException e)
此行无法访问。时间:
FileNotFoundException extends Exception
请参阅Exception和FileNotFoundException:
您可能想要切换订单。
答案 1 :(得分:6)
你的问题出在其他地方。 FileNotFoundException
将始终捕获Exception
,因为这是所有异常的基类。所以编译器基本上抱怨一段死代码
catch(FileNotFoundException e) {
System.out.println("File Not Found Caught");
}
一般来说,抓住Exception
不是一个好主意,你应该总是尝试进行更细粒度的expcetion处理,所以删除它并离开那里FileNotFoundException
阻止
答案 2 :(得分:4)
您的编译器可以看到此异常已被前一个catch块捕获。
当您捕获Exception
时,它还会捕获任何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());
}
答案 3 :(得分:2)
回答
我的问题是编译器是如何知道try块会抛出“FileNotFoundException”的?
您需要查看FileInputStream
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
注意它throws FileNotFoundException
。此声明告诉编译器可能抛出FileNotFoundException
,因此请确保使用try-catch
块处理它,或者使用另一个throws
子句在方法堆栈上冒泡。
至于你得到的错误,请查看所有其他答案。
答案 4 :(得分:2)
这里有几件事情在发挥作用。
首先,由于FileNotFoundException
构造函数的方法签名,编译器知道可能抛出FileInputStream
。来自the docs:
public FileInputStream(String name) throws FileNotFoundException
因此,签名告诉编译器它可以抛出FileNotFoundException
。
但是,在这种情况下,由于catch
块的排序,该信息实际上并不重要。你有:
catch(Exception e) { /* ... */ }
catch(FileNotFoundException e) { /* ... */ }
catch
阻塞工作的方式,如果在try
块中抛出异常,则执行遍历每个cacth
块并查看{{}中的异常类型1}} block是抛出异常的多态匹配。由于catch
来自FileNotFoundException
(请参阅here),因此它与第一个块匹配并始终匹配。因此,第二个块是不可达的。
因此,即使编译器不知道可以抛出Exception
,它仍然可以推断出第二个FileNotFoundException
块无法访问,因为任何{{扔掉的东西总是被第一个抓住。
定义catch
块时,请始终将它们按最具体的顺序排列,以避免出现此问题。
答案 5 :(得分: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中所有异常类的超类型。因此,可以将任何异常对象分配给类型为Exception
的引用。当程序中发生异常时,将从上到下依次检查catch块,以查找发生的异常类型与catch
块正在处理的异常类型之间的匹配。因此,try块中生成的任何类型的异常总是会找到第一个catch块作为匹配项,并且永远无法从您的代码中找到第二个catch块。这正是编译器抱怨的原因。
答案 6 :(得分: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());
}
答案 7 :(得分:0)
这不是重点:catch(Exception e)
也会抓住任何Exception
,即FileNotFoundException
。因此,第二次捕获FileNotFoundException
是无用的。
先抓住FileNotFoundException
,然后抓住Exception
。
答案 8 :(得分:0)
catch块将拦截指定类及其所有子类的异常。正如其他提到的FileNotFoundException
是Exception
的子类,所以它将被
catch (Exception e)
子句。
答案 9 :(得分:0)
Java Virtual Machine Specification: Exceptions
Java虚拟机中的每个方法都可以与零或 更多异常处理程序。异常处理程序指定范围 抵消实现该方法的Java虚拟机代码 异常处理程序处于活动状态,描述了异常的类型 异常处理程序能够处理,并指定 处理该异常的代码的位置。例外 如果指令的偏移量匹配异常处理程序 导致异常处于异常的偏移范围内 handler和exception类型是相同的类或子类 异常处理程序处理的异常类。当一个 抛出异常,Java虚拟机会搜索匹配项 当前方法中的异常处理程序。如果是匹配的异常 找到handler,系统分支到异常处理代码 由匹配的处理程序指定。
搜索方法的异常处理程序的顺序 比赛很重要。在类文件中,异常处理程序 每个方法都存储在一个表中(§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
其中from
和to
是指令编号。该表格自上而下搜索。