- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
**摘要:**文章的标题看似自相矛盾。
本文分享自华为云社区《Java异常处理:如何写出“正确”但被编译器认为有语法错误的程序》,作者: Jerry Wang 。
文章的标题看似自相矛盾,然而我在“正确”二字上打了引号。我们来看一个例子,关于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>使用了一个泛型语法,Textends 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语句捕捉住了。
这个问题不太可能帮助任何 future 的访问者;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况有关,这些情况并不普遍适用于互联网的全局受众。为了帮助使这个问题更广泛地适用,visit
class Person def name puts "Doharey" end end puts Person.class #=> this out puts Class puts
在 PHP 中,($myvariable==0)当 $myvariable 为零时,表达式的值为真;当 $myvariable 为 null 时,此表达式的值也为 true。如何排除第二种情况?我的意
正文 Oracle的一顿猛如虎操作,让开发者彻底失去了Java EE。Eclipse基金会则自立门户,另起炉灶开启Jakarta EE项目。 对于Jakarta EE,从它
我是 python 新手,建议我使用 Canopy。我正在努力跟进 with this tutorial ,但我陷入了 mahotas.imread 行。我收到一个错误,说以这个结尾: Full er
上下文是我们想要跟踪应用程序的用户行为,因为它具有不同的功能。 为此,我们创建了一个自定义 Angular Directive(指令),例如myFunctionality并将 HTML 部分包装到此指
我正在尝试在文本字段中实现 google Places api 的自动完成功能。这是我的代码: $(document).ready(function() { initialize(){ v
我在 Glassfish 3.1.1 中配置了一个新的 jdbcRealm 并打开了 FINEST 日志记录,当我尝试使用用户名和密码登录时,我得到以下信息。它提示我的 Web 应用程序映射到的领域是
问题是,即使我将线程设置为“thrd.IsBackground = false”,iis 也不认为它正在运行,即使这是一个长时间运行的进程。如果我不关闭应用程序池的空闲关闭,它将关闭,因为它认为它是空
我正在使用 OpenJDK 8(从 https://jdk.java.net/java-se-ri/8 下载并解压,添加到 PATH),并且遇到了证书错误。 经过调查,我意识到 cacerts 存在问
我基于 Firebase 制作了简单的后期制作项目。我将帖子保存到 Firebase 中,如下所示: let data = UIImageJPEGRepresentation(newPostImage
我觉得还是先说明情况比较好。 情况 我正在编写一些软件来过滤 Set 的 File。 过滤器如下:如果文件未隐藏,则将其添加到新的 Set。 问题在于 File.isHidden() 的当前行为如下:
我创建了一个 C++ DLL 函数,它使用多个数组来处理最终的图像数据。我正在尝试通过引用传递这些数组,进行计算,然后通过预分配数组中的引用将输出传回。在该函数中,我使用了 Intel Perform
我在 python 中有一个小应用程序,除了这个小问题之外,它工作得很好:它应该连续运行一个循环,直到用户通过按钮告诉它停止,但是当我点击开始按钮时,Windows 告诉我它不是回应。现在,如果我编写
代码运行正常,但我怎么会得到这个错误日志 错误日志: 08-28 08:44:24.281: E/MediaPlayer(32454): mOnVideoSizeChangedListener is
我有一个使用 Karma+Jasmine 和 JSHint 的 Grunt 设置。每当我在我的规范文件上运行 JSHint 时,我都会收到一系列“未定义”错误,其中大部分是针对 Jasmine 的内置
将以下代码保存到文件中,Ubuntu 14.04 正确地意识到它是 bash: #!/usr/bin/env bash awk '{print $1 $2}' my_file 然而,向 awk 添加关
以下代码返回 false import inspect print(inspect.isbuiltin(map)) 但是 map 功能在"built-in" functions下列出. 为什么会这样?
这是一段常见的示例代码: while (1) { print "foo\n"; } 永远打印“foo”。 perl foo.pl foo foo foo ... 和 while (0) { p
我对 Haskell 比较陌生,来自 F#(一种 Microsoft 语言)。 我已经从脚手架创建了一个 Yesod 项目,稍微玩了一下,调整了一些东西,但随后它停止工作,并显示此错误消息(在所有模块
我是一名优秀的程序员,十分优秀!