【问题标题】:Unexpected order of errors in java compilationjava编译中的意外错误顺序
【发布时间】:2026-02-15 03:45:01
【问题描述】:

在在线解决挑战时,我观察到 java 的以下行为,我觉得有点奇怪。我首先按照以下大纲编译了一个程序:

import java.io.*;

class WeirdJava
{
    public static void main (String[] args) 
    {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String input = br.readLine();
        HashMap<Integer, Integer> map = new HashMap<Integer,Integer>();
        System.out.println("Weird Java");
    }
}

注意,在上面的程序中,有两个错误:

  • 我没有处理BufferedReader 可能抛出的异常。
  • 我没有导入包含HashMap 的标准util 库。

现在,当我尝试编译上述程序时,java 编译器给出了找不到符号HashMap 的错误。请注意,涉及HashMap 的声明位于BufferedReader 之后。接下来,我将以下导入语句添加到程序中:

import java.util.HashMap;

当我再次编译程序时,这次编译器显示错误

未报告的异常IOException;必须被抓获或被宣布为 扔了

我的问题:

  1. 为什么在之前的编译尝试中没有抛出这个错误?
  2. 编译错误出现的顺序似乎不自然。在这个例程中发挥作用的编译器设计原则是什么?

【问题讨论】:

    标签: java compilation compiler-errors


    【解决方案1】:

    这只是编译器检查源代码的顺序。特别是,编译器会在检查调用可能引发检查异常的方法的代码之前检查导入并解析它们。

    如果您使用-verbose 运行javac,您会注意到编译器会加载导入的类,在本例中为BufferedReaderInputStreamReader,然后它会加载公共API 类,如Object 和@987654328 @:

    [loading ZipFileIndexFileObject[C:\Dev\Java\jdk1.7.0_75\lib\ct.sym(META-INF/sym/rt.jar/java/io/BufferedReader.class)]]
    [loading ZipFileIndexFileObject[C:\Dev\Java\jdk1.7.0_75\lib\ct.sym(META-INF/sym/rt.jar/java/io/InputStreamReader.class)]
    ]    
    [loading ZipFileIndexFileObject[C:\Dev\Java\jdk1.7.0_75\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Object.class)]]
    [loading ZipFileIndexFileObject[C:\Dev\Java\jdk1.7.0_75\lib\ct.sym(META-INF/sym/rt.jar/java/lang/String.class)]]
    [checking test.Test]
    [loading ZipFileIndexFileObject[C:\Dev\Java\jdk1.7.0_75\lib\ct.sym(META-INF/sym/rt.jar/java/lang/AutoCloseable.class)]]
    [loading ZipFileIndexFileObject[C:\Dev\Java\jdk1.7.0_75\lib\ct.sym(META-INF/sym/rt.jar/java/lang/System.class)]]
    [loading ZipFileIndexFileObject[C:\Dev\Java\jdk1.7.0_75\lib\ct.sym(META-INF/sym/rt.jar/java/io/InputStream.class)]]
    [loading ZipFileIndexFileObject[C:\Dev\Java\jdk1.7.0_75\lib\ct.sym(META-INF/sym/rt.jar/java/io/Reader.class)]]
    Test.java:11: error: cannot find symbol
        HashMap<Integer, Integer> map = new HashMap<Integer,Integer>();
    

    通过查看this link 中的概述,加载使用的类本身是称为“Parse and Enter”的第一阶段编译的一部分:

    每棵树都被传递给 Enter,它会将遇到的所有定义的符号输入到符号中。这必须在分析可能引用这些符号的树之前完成。此阶段的输出是一个待办事项列表,其中包含需要分析并生成类文件的树。

    【讨论】:

    • 为什么编译器不告诉这个 pass 本身的未捕获异常?
    • @Bhoot 我能想到的唯一原因是它还没有达到检查未捕获异常的阶段。遇到没有导入的类型时立即返回。
    • 我不同意这个理由,但似乎不自然。我将欣赏任何涉及该主题(或与之相关的任何内容)的文献。
    • @Bhoot 这是关于编译阶段的overview
    • 感谢您的链接。我现在不接受你的回答,因为我还不满意。仍然需要进行一些挖掘工作。