Kotlin 中那些无法复现的 Java 写法
· 阅读需 6 分钟
大家吼哇!了解 Kotlin 的朋友们都知道,Kotlin 对 Java 是 100% 兼容的,正如官方所说。 可即便如此,这就代表 Java 中所有的写法就都能在 Kotlin 中复现出来吗?倒也未必。 今天我就来简单盘点一些我发现的那些在 Kotlin 中无法复现出来的 Java 写法。
泛型异常
众所周知,Java 中有一个争议多年的东西:throws
。当它在函数后面声明了若干受检异常后,它便会向外传播,直到被捕获。
在 Java 中,你可以通过如下写法实现一个基于泛型的 throws
,以达到让调用者自行决定是否抛出受检异常的目的:
public static <T extends Exception> void runAndThrow(int value, Supplier<T> ex) throws T {
if (value == 0) {
throw ex.get();
}
}
可以看到,我定义了一个 runAndThrow
,里面包括了一个约束为 Exception
的泛型 T
,并且将 T
声明在 throws
处。
此时这个函数是否要求异常受检就取决于 T
的类型了。
public static void runThrowException(int value) throws Exception {
// 受检,因此也要 throws
runAndThrow(value, Exception::new);
}
public static void runThrowRuntimeException(int value) {
// runtime 异常不受检,因此不需要 throws
runAndThrow(value, RuntimeException::new);
}
那么这个写法可以在 Kotlin 中被复现吗?
首先一点需要说明的是,Kotlin 本身并不存在 “受检异常” 这个概念,也因此,实际上 Kotlin 中并没有 throws
这个关键词,
你可以随时抛出一个 Java 中的受检异常而不需要考虑它的传播问题。
fun runAndThrow() {
throw Exception()
}
但是这并不代表在 Kotlin/JVM 中就没有产生 throws
的方法。Kotlin 提供了一个注解 Throws
,用来告诉编译器在 JVM 中为它生成 throws
。
例如:
@Throws(Exception::class)
fun runAndThrow() {
throw Exception()
}
会被编译为类似下述代码的形式:
public void runAndThrow() throws Exception {
throw Exception();
}
聪明的你可能已经发现问题所在了。既然 Kotlin 将 throws
变成了注解,那么泛型就失去效果了,因为注解中无法指定函数上定义的泛型。
例如下面的写法,是无法通过编译的:
@Throws(T::class)
fun <T : Exception> runAndThrow(v: Int, ex: () -> T) {
if (v == 0) {
throw ex()
}
}