为什么Java8和Scala2.12 lambda缓存有区别?

时间:2016-11-24 06:36:29

标签: scala lambda java-8 jvm invokedynamic

Java代码

package lambda_cache_example_java;

interface Semigroup1<A> {
  public A append(A a1, A a2);
}

interface Semigroup2<A> {
  public A append(A a1, A a2);

  public interface Foo{}
  public class Bar{}
}

class Main {
  static Semigroup1<Integer> intSemigroup1() {
    return (a1, a2) -> a1 + a2;
  }

  static Semigroup2<Integer> intSemigroup2() {
    return (a1, a2) -> a1 + a2;
  }

  public static void main(String[] args) {
    Semigroup1<Integer> x1 = intSemigroup1();
    Semigroup1<Integer> x2 = intSemigroup1();
    System.out.println(x1);
    System.out.println(x2);
    System.out.println(x1 == x2); // same instance

    Semigroup2<Integer> y1 = intSemigroup2();
    Semigroup2<Integer> y2 = intSemigroup2();
    System.out.println(y1);
    System.out.println(y2);
    System.out.println(y1 == y2); // same instance as well
  }
}

Scala代码(版本2.12.0)

package lambda_cache_example_scala

trait Semigroup1[A] {
  def append(a1: A, a2: A): A
}

trait Semigroup2[A] {
  def append(a1: A, a2: A): A

  trait Foo
}

object Main {
  def intSemigroup1(): Semigroup1[Int] =
    (a1, a2) => a1 + a2

  def intSemigroup2(): Semigroup2[Int] =
    (a1, a2) => a1 + a2

  def main(args: Array[String]): Unit = {
    val x1 = intSemigroup1()
    val x2 = intSemigroup1()
    println(x1)
    println(x2)
    println(x1 eq x2) // same instance

    val y1 = intSemigroup2()
    val y2 = intSemigroup2()
    println(y1)
    println(y2)
    println(y1 eq y2) // not same
  }
}

结果

$ sbt "runMain lambda_cache_example_java.Main" "runMain lambda_cache_example_scala.Main"
[info] Running lambda_cache_example_java.Main 
lambda_cache_example_java.Main$$Lambda$9/1908283686@44939bb7
lambda_cache_example_java.Main$$Lambda$9/1908283686@44939bb7
true
lambda_cache_example_java.Main$$Lambda$10/2119574930@7f206457
lambda_cache_example_java.Main$$Lambda$10/2119574930@7f206457
true
[success] Total time: 0 s, completed 2016/11/24 15:09:56
[info] Running lambda_cache_example_scala.Main 
lambda_cache_example_scala.Main$$$Lambda$11/2085010450@7b408c6e
lambda_cache_example_scala.Main$$$Lambda$11/2085010450@7b408c6e
true
lambda_cache_example_scala.Main$$anonfun$intSemigroup2$2@c5329e5
lambda_cache_example_scala.Main$$anonfun$intSemigroup2$2@752d3cd9
false
[success] Total time: 0 s, completed 2016/11/24 15:09:57

1 个答案:

答案 0 :(得分:3)

Scala具有路径依赖类型。虽然从您的示例中并不明显,但可以构建嵌套特征,其中Foo内部的特征Semigroup2Foo的另一个实例中的Semigroup2完全不兼容。 1}}。 This postthis answer似乎是路径依赖类型的良好解释。

这意味着Semigroup2的实例也由其内部特征定义,因此在引用其中一个方法时必须进行闭包。由于每次我们尝试引用该方法时都会动态地重新关闭,因此匿名函数的不同并不令人惊讶。

在Java中,情况并非如此。 Semigroup2<A>.Foo是一种类型(与Scala不同,您需要实例 Semigroup[A]来标识类型Foo)。