根据JLS:如果命名类的实例变量初始值设定项或实例初始值设定项可以抛出已检查的异常类,则它是编译时错误,除非在throws子句中显式声明了该异常类或其一个超类。其类的每个构造函数和类至少有一个显式声明的构造函数。
所以,如果我这样做 -
class A{
{
throw new FileNotFoundException();
}
public A() throws IOException{
// TODO Auto-generated constructor stub
}
}
这给出了编译时错误“初始化程序必须正常完成”
,而
class A{
{
File f=new File("a");
FileOutputStream fo=new FileOutputStream(f);
fo.write(3);
}
public A() throws IOException{
// TODO Auto-generated constructor stub
}
}
此代码不显示任何编译时错误。为什么即使我在构造函数中声明了throws子句,前面的代码也不编译?
答案 0 :(得分:4)
初始化程序在没有任何异常的情况下实际完成时应该有一些条件。
在你的情况下,它无法发生。
尝试:
if(/*condition-to-fail*/) {
/*Not always, only when something is wrong. Compiler knows that.*/
throw new FileNotFoundException();
}
<强>更新强>
以下语句实际上是抛出异常。
throw new FileNotFoundException();
所以没有条件你的程序执行总是在那里结束。
在下面 -
FileOutputStream fo = new FileOutputStream(f);
构造函数FileOutputStream(File)
并不总是抛出该异常。
public FileOutputStream(File file) throws FileNotFoundException
中的throws子句只是说它可能会抛出该异常,并且只有在运行时才会找到该文件,否则它不会被发现。
答案 1 :(得分:2)
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.6
如果实例初始值设定项无法正常完成,则为编译时错误
http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.21
非空交换块的非空块可以正常完成,如果其中的最后一个语句可以正常完成。
...
if语句,无论是否有else部分,都以不寻常的方式处理。因此,本节末尾将单独讨论。
...
为了允许if语句方便地用于“条件编译”目的,实际规则不同。
...
答案 2 :(得分:1)
在第一种情况下,编译器已经知道实例初始化器永远不会正常完成,因为你已经明确地抛出了FileNotFoundException
。您可以说它是编译器的智能代码评估。但是如果你让编译器相信实例初始化器甚至有一点成功完成的机会那么编译器就不会在编译时抱怨。例如,在下面给出的代码中虽然我的目录中不存在文件IDonotexist.txt
,但我确信它会抛出FileNotFoundException
,但仍然编译器会让它成功编译。 为什么?因为在执行代码期间检查文件是否存在,而不是在编译时检查。
class A
{
{
FileReader fr = new FileReader(new File("IDonotexist.txt"));
}
public A() throws IOException
{
// TODO Auto-generated constructor stub
}
public static void main(String st[])throws Exception
{
A a = new A();
}
}
这类似于最终变量初始化的情况。对于以下代码中的示例,编译器将显示编译时错误
public void calling()
{
final int i;
int k = 90;
if ( k == 90)
{
i = 56;
}
System.out.println(i);//Compiler will show error here as: variable i might not have been initialized
}
但是如果我用if ( k == 90)
替换条件if(true)
,则编译器不会显示错误。因为编译器现在知道i
肯定会被分配一些值。