`
JerryWang_SAP
  • 浏览: 1043841 次
  • 性别: Icon_minigender_1
  • 来自: 成都
文章分类
社区版块
存档分类
最新评论

Java异常处理:如何写出“正确”但被编译器认为有语法错误的程序

阅读更多

文章的标题看似自相矛盾,然而我在“正确”二字上打了引号。我们来看一个例子,关于Java异常处理(Exception Handling)的一些知识点。

 

看下面这段程序。方法pleaseThrow接受一个Exception的实例,然后简单地将该实例抛出。然后调用这个方法时,我传入了一个SQLException的实例。因为pleaseThrow的调用包裹在一个try catch块里,

问题:plesseThrow方法抛出的SQLException可以成功被catch住么?

public class ExceptionForQuiz<T extends Exception> {

      private void pleaseThrow(final Exception t) throws T {

             throw (T) t;

      }

     public static void main(final String[] args) {

          try {

               new ExceptionForQuiz<RuntimeException>().pleaseThrow(new SQLException());

          }

         catch( final SQLException ex){

              System.out.println("Jerry print");

              ex.printStackTrace();

        }

}

}
 

答案:上面这段代码有语法错误,不能通过编译!

 

我们来一步步分析。

Java类ExceptionForQuiz<T extends Exception>使用了一个泛型语法,T extends Exception意思是这个泛型类实例化的时候,传入的类型参数T必须是Exception以及它的子类。

我在实例化类ExceptionForQuiz时,传入的类型参数是RuntimeException。

RuntimeException在Java里是一种Unchecked异常,即使一个方法运行时可能会抛出RuntimeException,也不需要开发人员在方法前用代码显式声明。

看JDK RuntimeException的注释说的很清楚:Unchecked exceptions do NOT need to be declared in a method or constructor's clause if they can be thrown by the execution of the method or constructor.

这个作者Frank Yellin一定是个大牛。

 

因为泛型是 Java 1.5 版本才引进的概念,关于泛型有一个类型擦除的概念,即泛型信息只存在于代码编译阶段,编译之后的代码里,与泛型相关的信息会被擦除掉。比如之前泛型类中的类型参数部分如果没有指定上限,像这种写法<T>, 则会被转译成普通的Object类型。如果指定了上限如<T extends String>则类型参数就被替换成类型上限。

为了简化起见,我们先把代码里的try catch块去掉。

 

下面是从ExceptionForQuiz.class反编译之后的代码:

 

我们从上图能观察到,方法pleaseThrow和雷ExceptionForQuiz的泛型参数RuntimeException已经被擦除掉了。pleaseThrow这个方法能抛出的异常类型已经被擦除成为Exception了。

使用javap观察编译生成的字节码,同样能发现类型参数RuntimeException被擦除的事实:

看第二个红色高亮区域:Exceptions: throw java.lang.Exception

 

现在我们来看编译器会报什么错误消息:Unreachable catch block for SQLException. This exception is never thrown from the try statement body.

 

根据异常类型擦除的事实,这个错误消息是合理的,因为pleaseThrow方法的声明现在只能抛出类型为Exception的异常,所以第14行的catch永远也没有办法接收到类型为SQLException的异常,所以编译器抛出错误。

如何消除掉这个编译器错误呢?把第14行的SQLException改成RuntimeException即可。

但是这样的话,虽然消除了语法错误,但是方法pleaseThrow抛出的SQLException没有办法被catch住,会报运行时错误:

 

如何把pleaseThrow抛出的SQLException也用catch语句接住呢?将第14行的RuntimeException改成所有异常的超类:Exception。

再次执行,这次既没有语法错误,也没有运行时错误了:SQLException已经成功地被第14行的catch语句捕捉住了。

 

要获取更多Jerry的原创技术文章,请关注公众号"汪子熙"或者扫描下面二维码:

 

 
 
0
0
分享到:
评论

相关推荐

    在静态编译器中实现Java异常机制的算法.pdf

    在静态编译器中实现Java异常机制的算法 Java 异常机制是 Java 语言中的一种重要机制,用于处理程序中的异常情况。在静态编译器中实现 Java 异常机制可以提高 Java 程序的执行效率和可靠性。下面将对在静态编译器中...

    Java编译器 词法分析 语法分析.zip

    1. **语义分析(Semantic Analysis)**:此阶段检查源代码的逻辑意义,如类型匹配、作用域规则、异常处理等,确保程序在逻辑上是正确的。 2. **中间代码生成**:编译器可能将源代码转换为中间表示(IR,...

    Java异常处理.pdf

    对异常的处理有两种方式:捕获处理异常和抛出异常。捕获和处理异常可以使用 try...catch...finally 结构来实现,语句格式为: ``` try { 可能出现异常的语句 } catch (异常类名 异常对象名) { 异常类中处理代码 } ...

    java程序错误类型及异常处理参考.pdf

    Java程序的错误类型主要分为语法错误、运行错误和逻辑错误,每种错误都有其特定的特征和处理方式。 1. **语法错误**:这是最基本的错误类型,发生在编程时输入的代码不符合Java语法规则。例如,括号不匹配、缺少...

    MiniJava编译器

    MiniJava编译器专注于MiniJava语言,这是一种简化版的Java,去除了某些复杂特性,如多线程、异常处理等,便于教学和理解。 2. **编译器的阶段**:一个标准的编译器通常包括词法分析、语法分析、语义分析和代码生成...

    java程序错误类型及异常处理归类.pdf

    Java程序错误类型及异常处理是编程过程中不可或缺的部分,它涉及到程序的正确性和稳定性。错误主要分为三类:语法错误、运行错误和逻辑错误。 1. **语法错误**是最直观的,它们在程序编译阶段就会被发现。编译器会...

    JAVA异常处理原因方法

    - **逻辑错误**,尽管这类错误的代码在语法上是正确的,但在逻辑上存在缺陷,可能导致程序运行结果不符合预期,例如错误的条件判断或循环控制。 #### 异常的概念与分类 异常是在程序执行过程中遇到的未预见情况,...

    编译原理编译器Java实现设计报告

    这些测试用例可以帮助验证编译器是否正确地处理了各种输入,并且在遇到错误时能给出清晰的错误消息。 总结来说,本设计报告中的Java编译器实现涵盖了编译器设计的关键步骤:词法分析、语法分析、语义分析和代码生成...

    基于测试C程序的java编写的词法编译器

    在这个特定的项目中,我们有一个基于Java编写的词法编译器,专门用于处理C语言的源代码。 首先,我们要理解词法分析器的工作原理。词法分析器通常读取源代码文件,并识别出关键字(如`if`、`for`)、标识符(用户...

    java基础语法选择题

    未初始化的局部变量不能直接使用,编译器会抛出错误。 - **b) 运行时出现异常**: 错误。这将是一个编译错误而不是运行时异常。 - **c) 正常运行,输出i=-1**: 错误。局部变量不支持默认初始化。 - **d) 正常运行,...

    用java语言写的语法分析器

    5. **异常处理**:Java有丰富的异常处理机制,语法分析器需要处理try-catch-finally语句块。 6. **包和导入**:Java使用包来组织类,import语句用于引入其他包中的类。 7. **注释**:Java支持单行注释、多行注释和...

    基于MINIJAVA转MIPS的编译器

    MINIJAVA是Java的一个子集,保留了类定义、方法声明、变量声明、基本数据类型、条件语句、循环语句等核心元素,但去除了如异常处理、多线程等复杂特性,便于初学者学习和理解编译器的工作原理。编写MINIJAVA编译器的...

    java教学课件第章异常处理机制完美版资料.ppt

    Java异常处理机制是Java编程中不可或缺的一个重要组成部分,它为开发者提供了一种处理程序运行时可能出现错误的有效方式。本章主要介绍了Java中的错误类型、异常的概念、异常类的层次结构以及异常处理的基本方法。 ...

    PL0词法分析器(java实现)

    Java的异常处理机制和类库可以简化错误处理和输入验证,使得代码更健壮。 **PL0语言简介** PL0是一种极简的、命令式的编程语言,由编译原理的权威教材《编译器设计》的作者Alfred V. Aho、Monica S. Lam、Ravi ...

    反编译器,一款优秀的JAVA反编译器

    2. **准确性**:反编译器应能准确地还原复杂的语法结构,如循环、条件语句、异常处理和多线程代码。此外,它还需要正确处理泛型、匿名类、内联方法等Java特性。 3. **用户界面**:对于图形用户界面(GUI)反编译器...

    PL/X编译器源代码(Java版)

    3. 异常处理:类似C的`try-catch`结构,PL/X有异常处理机制来捕获和处理运行时错误。 4. SQL集成:PL/X可以直接嵌入SQL语句,进行数据查询和操作。 现在,我们转向Java实现的PL/X编译器。使用Java作为实现语言有...

    java 实现Pascal语法分析

    在Java中,我们还可以利用Java的异常处理机制来捕获和处理语法错误,提高用户体验。此外,为了方便调试和测试,可能还会有单元测试用例,确保每个解析规则都能正确执行。 在实现过程中,还需要考虑如何处理Pascal的...

    java语法大全,java语法,java编程基础,java入门

    这份"java语法大全"文档,结合了“java语法”,“java编程基础”,以及“java入门”等核心主题,旨在为初学者提供全面的学习资源,帮助他们理解和掌握Java语言的基本概念和高级特性。 首先,Java语法是学习Java的...

    java常见的语法错误

    1. **变量可能未初始化**:当一个变量被声明但未赋值就尝试使用时,编译器会抛出“可能未初始化”的错误。例如: ```java int i; System.out.println(i); ``` 解决方法是在使用变量前给它赋值。 2. **变量重复...

Global site tag (gtag.js) - Google Analytics