Java 8中异常类型推断的一个特殊功能 [英] A peculiar feature of exception type inference in Java 8

查看:167
本文介绍了Java 8中异常类型推断的一个特殊功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在本站点编写另一个答案的代码时,我遇到了这个特点:$ b​​
$ b pre $ static $ testSneaky(){
final Exception e = new Exception();
sneakyThrow(e); //这里没有问题
nonSneakyThrow(e); //错误:未处理的异常:java.lang.Exception
}

@SuppressWarnings(unchecked)
static< T extends Throwable> void sneakyThrow(Throwable t)抛出T {
throw(T)t;
}

static< T extends Throwable> void nonSneakyThrow(T t)抛出T {
throw t;

$ / code>

首先,我很困惑为什么 sneakyThrow 调用对编译器是可以的。当没有提及未经检查的异常类型的任何地方时,它推断出 T 有什么可能的类型?第二,接受这一点,为什么编译器会抱怨 nonSneakyThrow 调用?他们看起来非常相似。

解决方案

推断 sneakyThrow RuntimeException 。这可以从类型推断的语言规范( http ://docs.oracle.com/javase/specs/jls/se8/html/jls-18.html

首先,第18.1.3节:

lockquote

$ 形式的边界引发α纯粹是信息性的:它指示解析来优化α的实例化,以便尽可能不是检查的异常类型。

不会影响任何东西,但它指向了解决方案部分(18.4),该部分获得了有关推断的异常类型的更多信息,其中包含特殊情况:


...否则,如果绑定集包含则抛出αi,并且αi的正确上限至多为 Exception Throwable Object ,那么Ti = RuntimeException

这种情况适用于 sneakyThrow - 唯一的上限是 Throwable ,所以根据规范推断 T 为 RuntimeException 所以它编译。该方法的主体是无关紧要的 - 未经检查的转换在运行时成功,因为它实际上并没有发生,留下的方法可以击败编译时检查异常系统。



nonSneakyThrow 不会编译为该方法的 T 的下限为异常 code>(即 T 必须是异常的超类型,或异常本身),这是一个检查的异常,由于它被调用的类型,所以 T 被推断为异常


While writing code for another answer on this site I came across this peculiarity:

static void testSneaky() {
  final Exception e = new Exception();
  sneakyThrow(e);    //no problems here
  nonSneakyThrow(e); //ERRROR: Unhandled exception: java.lang.Exception
}

@SuppressWarnings("unchecked")
static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
  throw (T) t;
}

static <T extends Throwable> void nonSneakyThrow(T t) throws T {
  throw t;
}

First, I am quite confused why the sneakyThrow call is OK to the compiler. What possible type did it infer for T when there is no mention anywhere of an unchecked exception type?

Second, accepting that this works, why then does the compiler complain on the nonSneakyThrow call? They seem very much alike.

解决方案

The T of sneakyThrow is inferred to be RuntimeException. This can be followed from the langauge spec on type inference (http://docs.oracle.com/javase/specs/jls/se8/html/jls-18.html)

Firstly, there's a note in section 18.1.3:

A bound of the form throws α is purely informational: it directs resolution to optimize the instantiation of α so that, if possible, it is not a checked exception type.

This doesn't affect anything, but it points us to the Resolution section (18.4), which has got more information on inferred exception types with a special case:

... Otherwise, if the bound set contains throws αi, and the proper upper bounds of αi are, at most, Exception, Throwable, and Object, then Ti = RuntimeException.

This case applies to sneakyThrow - the only upper bound is Throwable, so T is inferred to be RuntimeException as per the spec, so it compiles. The body of the method is immaterial - the unchecked cast succeeds at runtime because it doesn't actually happen, leaving a method that can defeat the compile-time checked exception system.

nonSneakyThrow does not compile as that method's T has got a lower bound of Exception (ie T must be a supertype of Exception, or Exception itself), which is a checked exception, due to the type it's being called with, so that T gets inferred as Exception.

这篇关于Java 8中异常类型推断的一个特殊功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆