转载

你不知道 Java 10 的 5 件事

局部变量类型推断是有争议的热点,但Java 10在JVM中的垃圾收集和容器识别上带来了可喜的变化。

关于本系列

所以你认为你了解Java编程? 事实是,大多数开发人员只是浮于Java平台的表面上,仅仅为了完成工作而学习。在这个正在进行的系列中,Java技术深入挖掘了Java平台的核心功能,提出了一些技巧和诀窍,可以帮助你解决即使是最棘手的编程挑战。

Java™ 开发人员已经习惯了等待新的Java版本发布,但是新的、高频率的发布节奏改变了这一情况。 Java 9出现之后仅仅过去6个月,现在Java 10已经在敲门了。 再过6个月,我们将迎来Java 11。 一些开发人员可能会发现这样的快速发布是多余的,但是新的节奏标志着一个长期需求的改变。

与它的版本号一样,Java 10提供了10个新特性,本文提供了我认为最重要的5个特性(您可以在 Open JDK 10项目页面 上查看它们)。

1. Java的新版本节奏

从历史上看,JDK发行的节奏是由大的新特性驱动的。 作为最近的例子,Java 8以lambda和流的形式引入了函数式编程,而Java 9引入了模块化Java系统。 每个新版本都被热切地期待着,但是次要的修复程序经常束之高阁,等待更大的组件版本被最终确定。 Java的进化落后于其他语言。

新的高频节奏将Java 以更小的增量 向前推进。 在发布日期准备好的特性将被包括在内,而那些不能被安排在下一个版本中,就在6个月之后。 在这个新周期下的第一个Java版本是Java 9,它于2017年10月发布。 Java 10于2018年3月发布,Java 11将于2018年9月发布。

作为新节奏的一部分,甲骨文表示,它将只支持每个主要版本,直到下一个主要版本发布为止。 当Java 11发布时,Oracle将停止支持Java 10。支持Java版本的开发人员必须每6个月迁移一次主要版本。 不希望或不需要频繁迁移的开发人员可以使用LTS(长期支持)版本,该版本每三年更新一次。 目前的LTS版本Java 8将在今年秋季发布Java 11之前得到支持。

2. 局部变量类型推断

局部变量类型推断是Java 10中最显着的特性。在进入JDK 10之前,争论非常激烈,该特性允许编译器推断局部变量的类型,而不是要求程序员明确指定它。

清单1 显示了如何在Java 10之前定义一个String变量类型。

清单1.声明并分配一个String类型的变量

String name = "Alex"

清单2展示了在Java10中 定义 与String类型相同的变量

清单2.用局部变量类型推断String类型的变量

var name = "Alex";

正如你看到的,唯一的区别就是使用了var保留类型名称。使用右边的表达式,编译器可以将变量名的类型推断为String。

这看起来有点简单,让我们来看一个更加复杂的例子。如果一个变量分配给了 调用 方法的返回值是怎样的?在这种情况下,编译器可以根据方法的返回类型推断变量的类型,如清单3所示。

清单3.从返回类型推断String类型

var name = getName();

String getName(){
    return "Alex";
}

使用局部变量类型

顾名思义,局部变量类型推断功能仅适用于局部变量。 它不能用于定义实例或类变量,也不能用于方法参数或返回类型。 但是,您可以在类和增强型循环中使用var,可以从迭代器中推断出类型,如清单4所示。

清单4.在循环中使用var

for(var book : books){}
for(var i = 0; i < 10; i++){}

使用这种类型的最明显的原因是为了减少代码中的冗长。 看看清单 5 中的示例。

清单 5. 很长的类型名称使得代码很长

String message = "Incy wincy spider...";
StringReader reader = new StringReader(message);
StreamTokenizer tokenizer = new StreamTokenizer(reader);

请注意,使用var保留类型名称重写清单5时发生了什么。

清单6. var类型减少了代码的冗长性

var message = "Incy wincy spider...";
var reader = new StringReader(message);
var tokenizer = new StreamTokenizer(reader);

清单6中的类型声明是垂直排列的,并且在构造函数调用的右侧每个申明中都会提到一次类型。 想象一下使用这种类型在一些Java框架中常见的长类名的好处。

局部变量类型的问题

1. var掩盖了类型

你已经看到了var如何提高代码的可读性,但是从另一方面来看,它也可以掩盖它。 看看清单7中的示例。

清单7.返回类型不清楚

var result = searchService.retrieveTopResult();

在清单7中,我们必须猜测返回类型。 让读者猜测发生了什么的代码是难以维护的。

2. var不能与lambda一起使用

与lambda表达式一起使用时,类型推断效果不佳,主要原因是编译器缺少类型信息。 清单8中的lambda表达式不会被编译。

清单8.类型信息不足

Function<String, String> quotify = m -> "'" + message + "'";
var quotify = m -> "'" + message + "'";

在清单8中,编译器的右边表达式中没有足够的类型信息来推断变量类型。 Lambda语句必须始终声明一个显式类型。

3. var不会与菱形操作符混在一起

与菱形操作符一起使用时,类型推断也不能很好地工作。 看看清单9中的例子。

清单9.使用带有var的菱形运算符

var books = new ArrayList <>();

亲自尝试一下

想要亲自尝试本地变量类型推断,您需要下载JDK 10和一个支持它的IDE。 IntelliJ的EAP(Early Access Program)版本具有此支持。 一旦你下载并安装了它,你可以从本文附带的GitHub存储库中检出代码开始。 你会在那里找到局部变量类型推断的例子。

在代码清单9中,books的ArrayList的参数类型是什么呢?你可能明白你是希望ArrayList存储一个书的列表,但是编译器不能推断出来。反之,编译器会做的唯一它能做的事情,就是推断出来这是一个参数是Object类型ArrayList:ArrayList<Object>()。

另外一种方法就是在右端表达式中的菱形运算符中定义具体类型。然后你可以让编译器从而推断出来变量的类型,就像在代码清单10中写的一样。或者使用另外一种方式,即你必须明确地以传统方式声明变量:List<Book> books。事实上,你可能更喜欢这种方式,因为它能让你定义一个抽象类型,并对List接口编程:

清单10. 定义出具体类型

var books = new ArrayList<Book>();
原文  https://www.oschina.net/translate/j-5things17
正文到此结束
Loading...