valhalla java_Amber、Valhalla和Loom,OpenJDK中的重要项目一览

OpenJDK中同时会有好几个项目在进行中。这些项目所带来的修改可能会加入到以后版本的JDK中。本文带你看一下OpenJDK中正在进行的重要项目,提前了解以后版本的JDK中会增加的功能。

Amber

Amber项目关注的是Java语言的小改动。Amber项目的一些成果已经被添加到JDK中。这其中包括:Java 10中的局部变量类型推断,也就是对var的使用。

Java 11中的允许在Lambda表达式的形式参数声明中使用var。

Java 12中的switch表达式。

Amber项目中正在探索的Java语言的改动包括模式匹配、数据类和密封类型和对序列化机制的改进。

模式匹配

熟悉Scala的人对模式匹配应该不陌生。Scala的模式匹配与case class一块使用,可以很简洁的把类型检查和数据提取结合起来。Java也在探索类似的功能。模式匹配由两个部分组成:表示匹配条件的断言(predicate)和匹配满足时提取数据的变量。

最简单的模式匹配规则是类型模式。在下面的代码中,如果x是Integer类型,则模式匹配成功,i是提取之后的Integer类型的对象。

if (x instanceof Integer i) {

// i是Integer类型}

更复杂的匹配模式是检查类型之后提取数据。在下面的代码中,如果n的类型是IntNode,那么IntNode中的字段i可以被提取出来,直接使用。

int eval(Node n) {

return switch(n) {

case IntNode(int i) -> i;

case NegNode(Node n) -> -eval(n);

case AddNode(Node left, Node right) -> eval(left) + eval(right);

case MulNode(Node left, Node right) -> eval(left) * eval(right);

};

}

数据类和密封类型

熟悉Kotlin的人看到数据类(data class)和密封类型(sealed type)肯定格外亲切。没有错,Java未来也会有数据类和密封类型。不过Java中的说法是记录类型,用关键字record表示。在下面的代码中,Expr是一个密封类型,ConstantExpr等是数据类。

sealed interface Expr { }

record ConstantExpr(int i) implements Expr { }

record PlusExpr(Expr a, Expr b) implements Expr { }

record TimesExpr(Expr a, Expr b) implements Expr { }

record NegExpr(Expr e) implements Expr { }

数据类有默认的equals、hashCode和toString实现。 使用sealed声明的类型限制了允许的子类型。

序列化机制

Java 自带的序列化机制是一个很糟糕的实现,以至于Java社区都选择忘记了这个功能的存在,而转而使用JSON、XML和ProtoBuf这样的外部序列化机制。Java的序列化机制会要进行修改,主要基于两个原则:需要进行序列化的是数据而不是对象。

序列化实现应该是对象模型的一部分。可以序列化的类应该清楚的定义自己的序列化和反序列化的行为。

下面代码中的Range类通过@Serializer和@Deserializer注解声明了序列化和反序列化的行为。Java运行时就可以知道两个int类型的字段hi和lo是序列化形式中的内容。

public class Range {

int lo;

int hi;

private Range(int lo, int hi) {

if (lo > hi)

throw new IllegalArgumentException(String.format("(%d,%d)", lo, hi));

this.lo = lo;

this.hi = hi;

}

@Serializer

public pattern Range(int lo, int hi) {

lo = this.lo;

hi = this.hi;

}

@Deserializer

public static Range make(int lo, int hi) {

return new Range(lo, hi);

}

}

Valhalla

与Amber项目对应的Valhalla项目中包含的是Java虚拟机上所做的探索。Valhalla项目中正在进行的探索主要是两个:内联类型和特殊化泛型。

内联类型

Java中区分了基本类型和引用类型。基本类型是int和long这样的,而引用类型都继承自Object。内联类型(inline type)给开发者的感觉是写起来像类,工作起来像int这样基本类型。 一个典型的例子是表示二维坐标的Point类。按照通常的设计,Point类有两个int字段分别表示X和Y轴的坐标。每个Point对象有自己的标识,并在Java堆上分配空间。Point对象所占用的内存空间大于两个int基本类型的空间。 这样的空间浪费在处理成百上千个Point对象时,就变得很可观。

在开发时,内联类型可像普通的类型一样工作;在运行时,Java虚拟机会用更有效的方式来存储。下面代码中的inline class用来声明内联类型。

public inline class Point {

int x;

int y;

public Point(int x, int y) {

this.x = x;

this.y = y;

}

}

泛型特殊化

泛型特殊化(Generic Specialization)是一个很有趣的话题。Java泛型目前的实现机制是类型擦除(type erasure)。类似List和List这样的类型,在运行时都只有List这一种表示形式。List在运行时是不可具体化的。泛型的一个限制是只能使用引用类型,也就是Object及其子类型。基本类型是不能使用的。所以List是错误的,只能使用对应的封箱类型,如List。只所以不能使用基本类型,是因为Java虚拟机对引用类型和基本类型操作的字节代码指令不同。

随着内联类型的引入,Java泛型可以扩展到支持基本类型。不过,这并不意味着完整的泛型特殊化实现。List仍然是不可具体化的。

Loom

Loom是本人最感兴趣的一个项目。Loom项目有3个主题,分别是计算续体(Continuation)、纤程(Fiber)和尾调用消除(tail-call elimination)。

计算续体是一段可以被暂停执行的代码。Java中的Continuation类使用Runnable表示需要执行的代码。在Runnable的实现中可以通过Continuation.yield()方法来暂停自己。每次调用Continuation对象的run(),所对应的代码要么运行到结束,要么运行到下一个yield()方法调用点。

在下面的代码中,Continuation对象cont的第一次执行会输出before,然后暂停;第二次执行会输出after,然后终止。

Continuation cont = new Continuation(SCOPE, () -> {

System.out.println("before");

Continuation.yield(SCOPE);

System.out.println("after");

});

while (!cont.isDone()) {

cont.run();

}

计算续体是低层次的结构,一般只供Java库的开发人员使用。一般的开发人员在日常编程中使用纤程。纤程可以看成是轻量级的线程。与线程相比,纤程的运行时额外开销更小,切换速度更快。Java应用中可以同时创建的纤程数量远远大于线程的数量。纤程是计算续体和调度器的整合。纤程可以与结构化并发性(Structured Concurrency)的思想结合起来,实现简洁易懂的并发代码。

尾调用消除可以通过复用函数栈来降低内存开销。这也是Loom项目的目标之一。

本文只是简单的介绍了Amber、Valhalla和Loom这3个OpenJDK的主要项目。除了这3个项目之外,还有其他比较小的项目也在进行中。关于这3个项目的细节,以及更多Java语言和Java平台的内容,请参与我在GitChat上的分享,只需要6元。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值