已检查异常和初始化块

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子句,先前的代码还是无法编译?


你告诉初始化块抛出无条件异常,你还能期望什么? - skuntsel
3个回答

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 可以工作。但为什么需要有条件语句?难道只抛出异常不行吗? - PermGenError
2
@PremGenError:这就像在一个没有条件检查的返回语句后编写代码一样。编译器也可以检测到这一点,这种情况也是如此。 - Bhesh Gurung
好的,但如果它总是抛出错误怎么办?我正在处理它。 - Salil Misra
@SalilMisra: "...总是抛出错误"。你能解释得更详细一些吗? - Bhesh Gurung
假设我写了一个 if(true) 语句,并抛出了异常,为什么这种情况是被允许的,而其他情况则不行呢? - Salil Misra
这就是条件检查的作用,并且它满足编译器所要求的要求。编译器的工作并不在意if语句中的结果表达式(该表达式仅在运行时评估)。 - Bhesh Gurung

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

非 switch 块的非空块可以正常完成,当且仅当其中的最后一条语句可以正常完成。

...

if 语句,无论是否有 else 部分,都以不寻常的方式处理。因此,在本节末尾单独讨论它。

...

为了方便地将 if 语句用于“条件编译”目的,实际规则有所不同。

...


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肯定会被赋值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接