在今年(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表达式的位置。
//Scala code
new Thread(() => println( "running" )).start
在Java代码中,可以使用Lamabda表达式作为函数对象应用在 =>
表达式的位置:
//Java code
scalaCollection.foreach(x-> println(x))
这样Scala和Java Lambda表达式实现了互操作。
之所以能这样替换,是因为Scala 2.12将lambda表达式编译的字节码和Java的字节码是一致的,而不是匿名函数的方式。
因此在Scala代码中,函数式接口(Functional interfaces,也叫SAM)都可以通过Scala的 =>
实现。
在看一个Java Stream中使用函数式接口SAM的例子:
// Java example:
stream.filter(s -> s.startsWith( "c" ))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);
在Scala中代码中我们使用 =>
实现这些SAM:
// 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 是函数式接口:
// Java code:
scalaCollection.foreach(x -> println(x));
在Scala 2.11中,要使用兼容包, JFunctionN 是函数式接口。
// Java code:
import static scala.compat.java8.JFunction.*;
scalaCollection.foreach(func(x -> println(x)));
编译Trait时使用缺省方法 (Make use of default methods ) 比如下面一个trait:
trait F1 {
def apply
def add(x:Int, y:Int) = x+y
}
会被编译成两个类:
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。一种就是
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正式发布后的实现方式。