Scala中的闭包vs Java中的闭包

问题描述:

前段时间,甲骨文决定为Java 8添加闭包将是一个好主意。我想知道如何解决设计问题与Scala相比,Scala从第一天起就已经关闭。Scala中的闭包vs Java中的闭包

援引开放的问题javac.info

  1. 能方法处理可用于功能类型? 如何做这项工作并不明显。一个问题是,方法处理reify类型参数,但以一种干扰函数子类型的方式。

  2. 我们可以摆脱“抛出”类型参数的显式声明吗? 只要声明的边界是一个检查的异常类型,这个想法就是使用disjuntive类型推断。这不是严格向后兼容的,但不太可能破坏真正的现有代码。然而,由于语法模糊性,我们可能无法摆脱类型参数中的“抛出”。

  3. 禁止在旧式的循环索引变量

  4. 手柄接口,如比较定义一种以上的方法,所有,但其中一个@Shared将由Object继承的方法来实现。 “使用单一方法的接口”的定义应该只计算在Object中不会实现的方法,并且应该将多个方法统计为一个,如果实现其中一个方法将全部实现它们。主要的是,这需要更精确地说明接口只有一个抽象方法意味着什么。

  5. 从指定函数类型映射接口:名称,参数等 我们完全应该精确地指定由函数类型系统生成的接口的映射。

  6. 类型推断。类型推断的规则需要增加以适应异常类型参数的推断。同样,封闭转换所使用的子类型关系也应该反映出来。

  7. 辅助异常类型参数,以帮助改进异常透明度。 也许make elided异常类型参数意味着界限。这样可以通过添加一个新的通用异常参数来修改没有异常类型参数的现有通用接口,如java.util.concurrent.Callable。

  8. 函数类型的类文字是如何形成的? 是否#void()。class?如果是这样,如果对象类型被擦除,它是如何工作的?是吗?(?)。class?

  9. 系统类加载器应动态生成函数类型接口。 函数类型对应的接口应该由引导类加载器按需生成,因此它们可以在所有用户代码之间共享。对于原型,我们可能会使用javac生成这些接口,以便原型生成的代码可以在库存(JDK5-6)VM上运行。

  10. 对lambda表达式的评估每次都必须产生一个新对象吗? 希望没有。例如,如果一个lambda从一个封闭范围捕获任何变量,它可以静态分配。同样,在其他情况下,如果lambda没有捕获循环内声明的任何变量,则可以将其移出内部循环。因此,如果规范对于lambda表达式的结果的引用标识没有任何承诺,那么这样的优化可以由编译器完成。

据我了解2,6和7不是Scala中的一个问题,因为Scala不使用检查异常作为某种“影子式系统”之类的Java。

其余的呢?

1)方法句柄可以用于函数类型吗?

Scala面向没有方法句柄的JDK 5和6,所以它还没有试图解决这个问题。

2)我们可以摆脱“throws”类型参数的显式声明吗?

Scala没有检查异常。

3)不允许在旧式循环索引变量上使用@Shared。

Scala没有循环索引变量。尽管如此,同样的想法可以用某种类型的while循环来表达。 Scala的语义在这里非常标准。捕获符号绑定,并且如果符号恰好映射到可变参考单元,那么就在您自己的头上。

4)手柄等比较限定多于一个的方法,其中除一个来自对象

Scala的用户往往使用的功能(或隐函数),来强迫正确类型的功能的接口接口。例如

[implicit] def toComparator[A](f : (A, A) => Int) = new Comparator[A] { 
    def compare(x : A, y : A) = f(x, y) 
} 

5)从函数类型指定映射到接口:

Scala的标准库包括FuncitonN性状0 < = N < = 22和规范说函数文本创建这些性状的实例

6)类型推断。类型推断的规则需要增加以适应异常类型参数的推断。

由于Scala没有检查过的异常可以在省略的异常类型的参数来帮助改进例外透明度这整个问题

7)踢。

同样处理,没有检查的例外。

8)函数类型的类文字是如何形成的?它是否#void()。class?如果是这样,如果对象类型被擦除,它是如何工作的?是吗?(?)。class?

classOf[A => B] //or, equivalently, 
classOf[Function1[A,B]] 

类型擦除是类型擦除。上述文字产生scala.lang.Function1不管A和B的选择如果愿意,可以编写

classOf[ _ => _ ] // or 
classOf[Function1[ _,_ ]] 

9)的系统,类装载器应该动态地生成功能类型的接口。

Scala可以将参数个数限制在22以下,这样它就不必动态生成FunctionN类。

10)每次都必须评估lambda表达式产生一个新对象吗?

斯卡拉规范并没有说它必须。但是从2.8.1开始,编译器不会优化lambda不能从其环境中捕获任何东西的情况。我还没有用2.9.0测试过。

我只会在这里解决数字4。

将Java“闭包”与其他语言中的闭包区分开来的一个原因是它们可以用来代替不描述函数的接口 - 例如Runnable。这就是SAM,单抽象方法的含义。

Java会这样做是因为这些接口在Java库中比比皆是,并且它们在Java库中比比皆是,因为 Java是在没有函数类型或闭包的情况下创建的。在他们缺席的情况下,需要反转控制的每个代码都必须使用SAM界面。

例如,Arrays.sort需要一个Comparator对象,该对象将执行要排序的数组成员之间的比较。相比之下,斯卡拉可以通过接收函数(A, A) => Int来对List[A]进行排序,该函数很容易通过闭包。但是,最后见注1。因此,因为Scala的库是为带有函数类型和闭包的语言而创建的,所以不需要像Scala中的SAM闭包那样支持这样的事情。

当然,还有一个Scala/Java互操作性的问题 - 而Scala的库可能不需要类似SAM的库,Java库。有两种方法可以解决。首先,因为Scala支持闭包和函数类型,所以创建辅助方法非常容易。例如:

def runnable(f:() => Unit) = new Runnable { 
    def run() = f() 
} 

runnable {() => println("Hello") } // creates a Runnable 

其实,这个特殊的例子,可以通过使用Scala的按姓名参数进行更短,但是这不是重点。无论如何,这可以说是Java可以做的事情,而不是它将要做的事情。鉴于SAM接口的普及,这并不令人惊讶。

Scala处理此问题的另一种方式是通过隐式转换。通过将implicit简单地添加到runnable方法中,只要需要Runnable,但是提供了函数() => Unit,就会创建一个自动获取(注2)的方法。

然而,牵涉是非常独特的,并且在一定程度上仍然存在争议。

注1:其实,这个特殊的例子是一些恶意选择... Comparator有抽象方法,而不是一个,这是整个问题的。由于其中一种方法可以用另一种方法来实现,我认为他们只是从抽象清单中“减去”防御者方法。

而且,在斯卡拉的一面,即使是使用(A, A) => Boolean,不(A, A) => Int排序方法,排序方法的标准要求一个Ordering对象,这是相当类似于Java的Comparator!但在斯卡拉的情况下,Ordering扮演类型的角色。

注意2:一旦它们被导入到范围中,将自动应用隐含,