我是从interview with Neal Gafter读到的:
“例如,使用Erasure作为泛型的一部分,将函数类型添加到编程语言要困难得多。”
编辑: 另一个我遇到类似陈述的地方是Brian Goetz的message in Lambda Dev mailing list,他说当lambdas只是一个带有句法糖的匿名类时,它们更容易处理:
但我对函数类型的反对意见并不是我不喜欢函数类型 - 我喜欢函数类型 - 但是函数类型与Java类型系统的现有方面,擦除有很大关系。删除的功能类型是两个世界中最糟糕的。所以我们从设计中删除了它。
任何人都可以解释这些陈述吗?为什么我需要lambdas的运行时类型信息?
答案 0 :(得分:6)
我理解它的方式是,他们认为,由于擦除,采用“功能类型”的方式会很麻烦,例如:在C#中委托,他们只能使用 lambda表达式,这只是单一抽象方法类语法的简化。
C#中的代表:
public delegate void DoSomethingDelegate(Object param1, Object param2);
...
//now assign some method to the function type variable (delegate)
DoSomethingDelegate f = DoSomething;
f(new Object(), new Object());
(此处的另一个示例 http://geekswithblogs.net/joycsharp/archive/2008/02/15/simple-c-delegate-sample.aspx)
他们在Project Lambda文档中提出了一个论点:
通用类型被删除,这将暴露其他地方 开发人员暴露于擦除。例如,它不会 可能使方法m(T-> U)和m(X-> Y)过载,这将是 混乱。
第2节: http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-3.html
(最终的lambda表达式语法与上面的文档略有不同: http://mail.openjdk.java.net/pipermail/lambda-dev/2011-September/003936.html)
(x, y) => { System.out.printf("%d + %d = %d%n", x, y, x+y); }
总而言之,我最好的理解是,只有部分语法内容可以实际使用。 Neal Gafter最有可能的意思是,无法使用委托将使标准API更难以适应功能样式,而不是javac / JVM更新将更难完成。
如果有人比我更了解这一点,我会很乐意阅读他的帐户。
答案 1 :(得分:2)
Goetz扩展了State of the Lambda 4th ed.中的推理:
功能类型的替代(或补充)方法, 一些早期提案建议,本来应该引入一个新的, 结构功能类型。类似“来自字符串和函数的函数” 对象为int“可以表示为(String,Object) - > int。这个 由于有几个想法,至少目前已经考虑并拒绝了这个想法 缺点:
- 这会增加类型系统的复杂性,并进一步混合结构和名义类型。
- 这将导致库样式的分歧 - 一些库将继续使用回调接口,而其他库将使用结构 功能类型。
- 语法可能不合适,尤其是在包含已检查的异常时。
- 不太可能存在每个不同函数类型的运行时表示,这意味着开发人员将进一步暴露 并且受到擦除的限制。例如,它是不可能的(也许是 令人惊讶地)重载方法m(T-> U)和m(X-> Y)。
所以,我们选择走“使用你的道路” 知道“ - 因为现有的库广泛使用功能接口, 我们编纂并利用这种模式。
为了说明,这里是Java SE 7中的一些功能接口 非常适合与新语言功能一起使用; 以下示例说明了其中一些示例的使用。
- 了java.lang.Runnable
- java.util.concurrent.Callable
- 了java.util.Comparator
- 的java.beans.PropertyChangeListener
- java.awt.event.ActionListener
- javax.swing.event.ChangeListener
- ...
请注意,擦除只是其中一个考虑因素。一般来说,Java lambda方法与Scala的方向不同,而不仅仅是键入的问题。它是以Java为中心的。
答案 2 :(得分:1)
也许是因为你真正想要的是一个类型Function<R, P...>
,它使用返回类型和一些参数类型参数化。但是由于擦除,你不能拥有像P...
那样的构造,因为它只能变成Object[]
,这太松散了,不能在运行时使用。
这是纯粹的猜测。我不是一个理论家;我甚至没有在电视上播放过。
答案 3 :(得分:-1)
我认为他在该声明中的意思是在运行时Java无法区分这两个函数定义:
void doIt(List<String> strings) {...}
void doIt(List<Integer> ints) {...}
因为在编译时,有关List包含的数据类型的信息将被删除,因此运行时环境将无法确定您要调用哪个函数。
尝试在同一个类中编译这两个方法将引发以下异常:
doIt(List<String>) clashes with doIt(List<Integer); both methods have the same erasure