那些年,Kotlin 都截胡了哪些 Java 新特性
众所周知,Kotlin被称为最好的 Java。自 Kotlin 发布以来,凭借着其在 JVM 平台上惊人的兼容性,互操作性以及新特性支持,其迅速成为了广泛使用的 JVM 语言之一,就连 Google 也将 Kotlin 钦定为 Android 的首选开发语言。Kotlin 相对 Java 提供了非常多的特性,这些特性甚至截胡了某些 Java 即将推出的新特性,现在就让我们来盘点一下这些被 Kotlin “截胡” 的 Java 新特性吧…
JEP 286: Local-Variable Type Inference
JEP 286: 本地变量类型推断 在 Java 10 发行,为在局部作用域的具有初始值的变量提供了自动类型推断:
代码语言:javascript复制var list = new ArrayList<String>(); // infers ArrayList<String>
var stream = list.stream(); // infers Stream<String>
Kotlin 则始终支持(无论在全局还是局部作用域)变量自动类型推断:
代码语言:javascript复制var list = ArrayList<String>(); // infers ArrayList<String>
val stream = list.stream(); // infers Stream<String>
JEP 325/354/361: Switch Expressions
JEP 361: Switch 表达式 在经过 Java 12 和 13 的两次预览后,终于在 Java 14 中发行,其允许一种增强的 switch 语法:使用 case … -> labels 的方式来表达分支以避免输入额外的 break;
语句;更重要的是,switch 语句支持作为表达式返回一个结果给变量:
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
default -> 0;
};
在 Kotlin 中则通过 when
语句获得同样的体验:
var numLetters: Int = when (day){
MONDAY, FRIDAY, SUNDAY -> 6;
TUESDAY -> 7;
THURSDAY, SATURDAY -> 8;
WEDNESDAY -> 9;
else -> 0;
}
JEP 355/368/378: Text Blocks
JEP 378: 文本块 在 Java 15 完成预览并最终发行,其提供了一种更好的描述多行字符串的方式,而不是通过添加 n
这样的转义序列表达:
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
在 Kotlin 中,文本块同样被支持:
代码语言:javascript复制var html: String = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""".trimIndent()
JEP 401: Primitive Classes (Preview)
JEP 401: 原始类(预览) 是一个尚在候选(Candidate)状态的 JEP 提案,其试图允许 Java 开发者创建像基本数据类型那样工作的类以提高包装对象的性能:
代码语言:javascript复制primitive class Point implements Shape {
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double x() { return x; }
public double y() { return y; }
public Point translate(double dx, double dy) {
return new Point(x dx, y dy);
}
public boolean contains(Point p) {
return equals(p);
}
}
interface Shape {
boolean contains(Point p);
}
Kotlin 则在 1.5.0 引入了 value class
的概念,允许为单一基本数据类型创建包装对象:
@JvmInline
value class Name(val s: String) {
init {
require(s.length > 0) { }
}
val length: Int
get() = s.length
fun greet() {
println("Hello, $s")
}
}
fun main() {
val name = Name("Kotlin")
name.greet() // method `greet` is called as a static method
println(name.length) // property getter is called as a static method
}
尽管此两者的运作方式和限制条件有很大的不同,但其目标事实上是相同的:希望减少包装器对象额外的内存使用,优化内存结构。
JEP 360/397/409: Sealed Classes
JEP 409: 密封类 在 Java 17 完成预览并最终发行,其允许限定哪些类和接口可以继承和实现它们,以此为其它语言特性提供更好的模式匹配推断:
代码语言:javascript复制public abstract sealed class Shape
permits Circle, Rectangle {...}
public class Circle extends Shape {...} // OK
public class Rectangle extends Shape {...} // OK
public class Triangle extends Shape {...} // Compile error
// No need for default case if all permitted types are covered
double area = switch (shape) {
case Circle c -> Math.pow(c.radius(), 2) * Math.PI
case Rectangle r -> r.a() * r.b()
};
Kotlin 也同样提供了密封类的功能,仅允许在同一个文件内的类继承/实现一个密封类/接口:
代码语言:javascript复制package pkg.a
sealed class Shape
class Circle : Shape() {...} // OK
class Rectangle : Shape() {...} // OK
package pkg.b
class Triangle : Shape() {...} // Compile error
// No need for default case if all permitted types are covered
var area = when (shape) {
is Circle -> Math.pow(shape.radius(), 2) * Math.PI
is Rectangle -> shape.a() * shape.b()
}
JEP 425: Virtual Threads (Preview)
JEP 425: 虚拟线程(预览) 在 Java 19 发行,其提供了一套有栈协程系统,以减少系统级调用线程带来的高开销。
Kotlin 提供了 Kotlin 协程以达到近似的目的,不过值得一提的是,Kotlin 协程是无栈协程,这意味着其在互操作性和使用内存大小上相比有栈协程会较差一些。
JEP 428: Structured Concurrency
作为 Project Loom 的一部分,与 JEP 425 一样,JEP 428: 结构化并发(孵化) 同样在 Java 19 发行,其提供了一套更好的 API 来处理多线程下的程序调度:
代码语言:javascript复制Response handle() throws ExecutionException, InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> user = scope.fork(() -> findUser());
Future<Integer> order = scope.fork(() -> fetchOrder());
scope.join(); // Join both forks
scope.throwIfFailed(); // ... and propagate errors
// Here, both forks have succeeded, so compose their results
return new Response(user.resultNow(), order.resultNow());
}
}
同样,Kotlin 协程也带来了类似的调度方式:
代码语言:javascript复制suspend fun handle() = coroutineScope {
val deferredOne = async {
delay(1000)
"String"
}
val deferredTwo = async {
delay(2000)
1
}
return@coroutineScope Pair(deferredOne.await(), deferredTwo.await())
}
JEP 430: String Templates
JEP 430: 字符串模板 (预览) 是一个尚在候选状态的 JEP 提案,其引入了一种间接方便的在字符串中嵌入表达式的方式:
代码语言:javascript复制String name = "Joan";
String info = STR."My name is {name}";
assert info.equals("My name is Joan"); // true
Kotlin 提供的字符串模板语法如下:
代码语言:javascript复制"x plusy equals ${x y}"
JEP 305/375/394: Pattern Matching for instanceof
JEP 394: instanceof 的模式匹配 在 Java 16 完成预览并最终发行,其引入了一种在指定作用域内使用 instanceof 进行的自动类型推断:
代码语言:javascript复制if (obj instanceof String s) {
// obj is cast to String as variable 's'
}
Kotlin 通过其 Smart Cast 机制自动完成类型推断:
代码语言:javascript复制lateinit var obj: Any
if (obj is String) {
obj.substring(1) // Smart cast to kotlin.String
}