2013-02-23 40 views
7

根据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

你告诉初始化块抛出无条件异常,你还期望什么? – skuntsel 2013-02-23 15:40:23

回答

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子句只是说它可能会引发该异常,并且只有在运行时文件没有找到时才会执行该操作。

+0

+1有效。但为什么我们需要有条件语句??不能只是抛出异常工作? – PermGenError 2013-02-23 15:40:36

+2

@PremGenError:这就像在没有条件检查的返回语句之后编写代码一样。编译器也可以检测到,在这种情况下也是如此。 – 2013-02-23 15:42:27

+0

不错...谢谢:) – PermGenError 2013-02-23 15:43:11

2

http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.6

It is a compile-time error if an instance initializer cannot complete normally

http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.21

A non-empty block that is not a switch block can complete normally iff the last statement in it can complete normally.

...

The if statement, whether or not it has an else part, is handled in an unusual manner. For this reason, it is discussed separately at the end of this section.

...

in order to allow the if statement to be used conveniently for "conditional compilation" purposes, the actual rules differ.

...

+0

+1仅给出实际原因的答案。 – assylias 2013-04-01 10:12:55

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(true)替换条件if (k == 90)然后编译器将不显示错误。因为编译器现在知道i肯定会被分配一些值。