Scala 2.12 拥抱 Java 8

在今年(2015)的旧金山的ScalaDays会议上,来自Scala核心团队的Lukas Rytz分享了一个演讲:The JVM Backend and Optimizer in Scala 2.12的技术细节,主要基于Java 8平台上一些改变, 比如Lambda, 缺省方法等。第二部分主要介绍了生成的字节码的优化。
本文是对第一部分做的笔记。
因为2.12还没有正式发布,一下特性可能还无法校验。

函数互操作 (Interop for functions: source and bytecode )

Scala 2.12只能运行在Java 8上。
Scala和Java8实现互操作。
在Scala代码中,可以使用=>表达式应用在Java Lambda表达式的位置。

1
2
//Scala code
new Thread(() => println("running")).start

在Java代码中,可以使用Lamabda表达式作为函数对象应用在=>表达式的位置:

1
2
//Java code
scalaCollection.foreach(x-> println(x))

这样Scala和Java Lambda表达式实现了互操作。

之所以能这样替换,是因为Scala 2.12将lambda表达式编译的字节码和Java的字节码是一致的,而不是匿名函数的方式。
因此在Scala代码中,函数式接口(Functional interfaces,也叫SAM)都可以通过Scala的 =>实现。

在看一个Java Stream中使用函数式接口SAM的例子:

1
2
3
4
5
// Java example:
stream.filter(s -> s.startsWith("c"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);

在Scala中代码中我们使用=>实现这些SAM:

1
2
3
4
5
6
7
// Scala
import java.util.stream.Stream
var s = Stream of ("a1","a2","b1","c2","c1")
s.filter(s => s.startsWith("c"))
.map(_.toUpperCase).sorted.forEach(println)

毫无违和感。

Java中使用Scala类库时遇到SAM时:
在Scala 2.12中, FunctionN是函数式接口:

1
2
// Java code:
scalaCollection.foreach(x -> println(x));

在Scala 2.11中,要使用兼容包,JFunctionN是函数式接口。

1
2
3
// Java code:
import static scala.compat.java8.JFunction.*;
scalaCollection.foreach(func(x -> println(x)));

编译Trait时使用缺省方法 (Make use of default methods )

比如下面一个trait:

1
2
3
4
trait F1 {
def apply
def add(x:Int, y:Int) = x+y
}

会被编译成两个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public abstract interface F1
{
public abstract void apply();
public abstract int add(int paramInt1, int paramInt2);
}
public abstract class F1$class
{
public static int add(F1 $this, int x, int y)
{
return x + y;
}
public static void $init$(F1 $this)
{
}
}

有几种方案来编译成SAM。一种就是

1
2
3
4
5
6
7
8
public interface F1
{
public abstract void apply();
public default int add(int paramInt1, int paramInt2) {
return F1$class.add(paramInt1, paramInt2)
}
}

或者直接编译成SAM,不需要一个辅助类F1$class

可以关注Scala 2.12正式发布后的实现方式。