Java类型推断将不再支持可变性规范

WinReibey 8年前
   <p>Java类型推断是一项推荐的Java特性,允许开发人员使用var关键字代替显式的变量类型声明。 最近的报道显示 ,由于社区内无法就区分可变和不可变变量的实现方式达成一致意见,Java类型推断将不再支持使用关键字区分可变的和不可变变量。提议的一些用来表示不可变变量的关键字包括val和let。为了避免对细枝末节的长期讨论,一些这样的例子将被排除以求简洁。尽管JEP并没有透露目标版本,Java 10可能会实现这些功能。</p>    <p>为了完整地定义 JEP 286 的范围,甲骨文公司的Java语言架构师Brian Goetz在经过了一系列的提议和咨询之后了解到,实现局部变量类型推断(和避免显式声明变量类型的步骤)的新功能已达成足够共识,该功能应该使用关键词var。另外,社区还强调了他们希望使用和其它语言,如Scala、Kotlin或JavaScript,一样的方式来区分可变和不可变变量的类型推理。然而,尽管大家赞同这是一个有用的功能,但是就如何实现该区分,没有一致的意见。var/val、var/let和(raw type)/var都有强烈的支持者和反对者。为了防止这种争论延迟类型推断的进展,该功能的主导者决定将范围缩小到局部变量的简单类型推断,不管可变性区别。尽管如此,使用稍长一点的构造final var,不可变的局部变量的类型仍然是可推断的。</p>    <pre>  <code class="language-java">var s = "hello"; // type of s is String  var keys = map.keySet(); // assuming map is of type Map<K, V>, type                            // inferred for keys will be Set<K>  final var MAX_COUNT = 100L; // MAX_COUNT will be immutable long</code></pre>    <p>更新还用于提醒可推断的程度。一方面,只有初始化信息将用于推断变量的类型;这意味着在声明时未初始化的变量需要显式声明类型,它也有助于防止一些潜在的晦涩的错误(例如,代码深处的变量的类型推断错误)。另一方面,只有局部变量的类型是可推断的,不包括属性和方法,这是基于如下理解的。属性和方法是类的公共接口的一部分,因此需要由程序员明确定义。类型推断不起作用的其他情况是,暗示自身类型的初始化表达式,如:</p>    <pre>  <code class="language-java">List<String> list = new LinkedList<>(); // type not indicated in                                          // initialisation, but inferred                                          // from variable declaration  var list = new LinkedList<>(); // error, impossible to infer a type for                                 // the contents of the list    Function<String, Integer> f = s -> s.length(); // type of s and length                                                 // inferred from                                                 // declaration  var f = s -> s.length(); // error, type of s unknown, return type of                           // length unknown    int[] array = {1, 2, 3}; // 1, 2, 3 interpreted as integers  var array = {1, 2, 3}; // error, poly expressions not supported                         // (see below)    // Use Integer.valueOf(int)  Function<Integer, Integer> intFunction = Integer::valueOf;    // Use Integer.valueOf(String)  Function<String, Integer> stringFunction = Integer::valueOf;     // error, ambiguous initialisation  var function = Integer::valueOf; // unable to know which overloaded                                   // version of valueOf should be used</code></pre>    <p>目前还不清楚是否将支持上述的某些特定例子。 如Goetz所说 ,“我们将初始化器看作一个独立表达式(standalone expression),通过获取它的类型得到变量的类型。然而,数组初始器与lambda和方法引用一样,是多变表达式(poly expression),所以被拒绝了。” 多变表达式 是Java 8中随着lambda引进的一个概念,与普通表达式的不同之处在于计算类型的方式。对于普通表达式来说,可以通过在编译时检查表达式的内容获取类型;对于多变表达式,要计算类型,除此之外还需要目标类型(即被表达式赋值的变量的类型)。这意味着,多变表达式已经隐含了一些对自身的类型推断,因此很难甚至不可能推断多变表达式的类型。但是,有一些这类问题的场景似乎提供了足以推断出合适类型的信息,可能将来会考虑把它们纳入进来。如下:</p>    <pre>  <code class="language-java">var a = {1, 2, 3}; // could infer type int[]  var f = (String s) -> s.length(); // could infer type                                    // Function<String, Integer></code></pre>    <p>尽管存在局限,局部类型推断能帮助缩小Java和其它JVM语言之间的差距,为Java开发人员减少冗余代码。和 lambda现在扩充新功能 的方式一样,类型推断可能在第一版之后得到提升。这将确认作为新功能实验场所的JVM语言的非官方动态,最流行的新功能最终被引入Java。</p>    <p> </p>    <p> </p>    <p>来自:http://www.infoq.com/cn/news/2017/01/java-type-inference-mutability</p>    <p> </p>