哈Ha! 我向您介绍Simon Ritter撰写的文章“ JDK 11中的90个新功能(和API) ”的翻译。

对于许多人来说,新的六个月JDK发布周期意味着有些人甚至还没有弄清JDK 10中有哪些新功能,而JDK 11即将到来。设法在JDK 10中找到它。因此,对于JDK 11,决定这样做。 但是,选择了不同的格式。 这篇文章将分为两部分:开发人员可以使用的新功能(公共API)以及其他所有功能。 因此,如果您只对直接影响开发的内容感兴趣,则可以跳过第二部分。
可以计算出的更改总数为90(这是JEP加上新的类和方法,不包括HTTP客户端和Flight Recorder的单独方法) 在JDK中,但从Java 11开始,这要归功于JEP 328 ,并将其转移到开源中) 。 尽管JDK 11设法发现的变化少于JDK 10,但我认为可以肯定地说是在JVM级别向JDK 11添加了更多功能。
开发人员应注意的新功能
JDK 11有很多可能影响开发风格的更改。 语法略有变化,提供了许多新的API,并且无需使用编译器就可以在一个文件中运行应用程序( 请注意翻译器:所谓的shebang文件 )。 另外,最大的变化(并且是重大的变化)是删除了java.se.ee聚合模块,这可能会影响现有应用程序向JDK 11的迁移。
JEP 323:Lambda参数的本地变量语法
在JDK 10中,引入了局部变量推断(或类型推断)( JEP 286 )。 这简化了代码,因为您不再需要显式指定局部变量的类型,而可以使用var 。 JEP 323扩展了此语法的使用,该语法现在也适用于lambda表达式的参数。 一个简单的例子:
list.stream() .map((var s) -> s.toLowerCase()) .collect(Collectors.toList());
细心的Java程序员会指出lambda表达式已经具有类型推断,因此(在这种情况下)使用var是多余的。 我们可以轻松地编写与以下代码相同的代码:
list.stream() .map(s -> s.toLowerCase()) .collect(Collectors.toList());
为什么要添加var支持? 答案是一种特殊情况-当您想向lambda参数添加注释时。 没有任何类型的参与就不可能做到这一点。 为了避免使用显式类型,我们可以使用var通过以下方式简化事情:
list.stream() .map((@Notnull var s) -> s.toLowerCase()) .collect(Collectors.toList());
此更改要求更改Java语言规范(JLS) ,尤其是:
第24页:var特殊标识符的描述。
页面627-630:Lambda参数
Lambda表达式的页面636:运行时评估
页面746:Lambda语法
JEP 330:启动单文件源代码程序
对Java的批评之一是语法的冗余,与启动甚至是琐碎的应用程序相关的“仪式”也可能严重增加初学者的入门门槛。 要编写仅打印“ Hello World!”的应用程序,您需要使用公共静态void main方法编写一个类,并使用System.out.println()方法。 完成此操作后,您必须使用javac编译代码。 最后,您可以启动一个欢迎世界的应用程序。 使用大多数现代语言运行同一脚本要简单得多,而且速度也快得多。
JEP 330消除了编译单个文件应用程序的需要。 现在只需输入:
java HelloWorld.java
Java启动器会识别该文件包含Java源代码,并在执行该代码之前将其编译为* .class文件。
当应用程序启动时,放置在源文件名后面的参数将作为参数传递。 编译代码后,将放置在源文件名称之前的参数作为参数传递给java启动器(这使您可以在命令行上设置诸如classpath之类的东西)。 与编译器相关的参数(例如classpath)也将传递给javac进行编译。
一个例子:
java -classpath /home/foo/java Hello.java Bonjour
等同于:
javac -classpath /home/foo/java Hello.java java -classpath /home/foo/java Hello Bonjour
该JEP还提供对shebang文件的支持。 为了减少甚至在命令行上提到Java启动器的需求,您可以将其包含在源文件的第一行中。 例如:
#!/usr/bin/java --source 11 public class HelloWorld { ...
必须带有所使用的Java版本的-source标志。
JEP 321:HTTP客户端(标准)
JDK 9引入了新的API以支持HTTP客户端协议( JEP 110 )。 由于JDK 9提供了Java平台模块系统(JPMS) ,因此将该API作为孵化器模块包括在内。 孵化器模块旨在提供新的API,但不要将其转变为Java SE标准。 开发人员可以通过提供反馈来尝试使用API。 进行必要的更改(此API在JDK 10中进行了更新)后,可以将该API转移到主模块以成为标准的一部分。
HTTP客户端API现在是Java SE 11标准的一部分,它为JDK引入了新的模块和软件包java.net.http 。 主要课程:
- Http客户端
- Http请求
- HttpResponse
- 网络插座
该API可以同步或异步使用。 在异步模式下,使用CompletionFutures和CompletionStages。
JEP 320:删除Java EE和CORBA模块
通过在JDK 9中引入JPMS,可以将整体式rt.jar文件拆分为几个模块。 JPMS的另一个好处是,您现在可以创建一个Java运行时环境,该环境仅包含应用程序所需的模块,从而大大减小了整体尺寸。 有了明确定义的边界,现在可以更容易地从Java API中删除过时的模块。 这就是JEP所做的; java.se.ee元模块包含六个模块,这些模块将不再是Java SE 11标准的一部分,并且不会包含在JDK中。
远程模块:
- corba( 译者注:
安息 ,在地狱中燃烧 ) - 交易
- 激活
- xml.bind
- xml.ws
- xml.ws.annotation
自JDK 9起,这些模块已标记为过时(@Deprecated),并且默认情况下未包含在编译或运行时中。 如果您尝试使用JDK 9或JDK 10上这些模块中的API编译或运行应用程序,那么您将失败。 如果您在代码中使用这些模块中的API,则需要将它们作为单独的模块或库提供。 从评论来看,似乎是最引起问题的模块是JAX-WS,SOAP Web服务支持的java.xml模块。
新的公共API
JDK 11中的许多新API是由于HTTP客户端模块现已成为标准的一部分以及包含Flight Recorder的结果。
可在此处找到 API更改的完整示意图列表,包括对JDK不同版本的比较。
这里列出的是除java.net.http和jdk.jfr模块中包含的那些方法以外的所有新方法。 同样未列出的是java.security模块中的新方法和类,它们专门针对JEP 324和JEP 329更改(有六个新类和八个新方法)。
java.io.ByteArrayOutputStream
- void writeBytes(byte []) :将参数中的所有字节写入OutputStream
java.io.FileReader
两个新的构造函数,可让您指定字符集。
java.io.FileWriter
四个新的构造函数,可让您指定字符集。
- io.InputStream nullInputStream() :返回一个不读取字节的InputStream。 查看此方法(以及OutputStream,Reader和Writer中的方法),就产生了一个问题,为什么它会派上用场。 您可以将它们视为/ dev / null-丢弃不需要的输出,或提供始终返回空字节的输入。
java.io.OutputStream
- io.OutputStream nullOutputStream()
java.io.Reader
java.io.Writer
java.lang.Character
- String toString(int) :这是现有方法的重载形式,但是使用int代替char。 Int是Unicode代码点。
java.lang.CharSequence
- int compare(CharSequence,CharSequence) :按字典顺序比较CharSequence的两个实例。 如果第一个序列在字典上小于,等于或大于第二个序列,则分别返回负值,零或正值。
java.lang.ref.Reference
- lang.Object clone() :我必须承认,这种更改会引起混乱。 Reference类未实现Cloneable接口,并且此方法引发CloneNotSupportedException。 必须将其包括在内,也许是将来的某些原因。 ( 译者注: 有关 OpenJDK中的票证 StackOverflow的讨论 )
java.lang.Runtime
java.lang.System
这里没有新方法,但是值得一提的是,现在两个类都删除了runFinalizersOnExit()方法(迁移到JDK 11时可能会出现问题)。
java.lang.String
我认为这是JDK 11中新API的亮点之一。这里有一些有用的新方法。
- boolean isBlank() :如果字符串为空或仅包含空格,则返回true,否则返回false。
- Stream lines() :从字符串返回Stream,从字符串中提取,并由行分隔符分隔。
- 字符串重复(int) :返回一个字符串,其值是此字符串的串联,重复多次。
- String strip() :返回一个值为该字符串的字符串,这将删除字符串开头和结尾的所有空格。
- String stripLeading() :返回一个值为该字符串的字符串,同时删除行首的所有空格。
- String stripTrailing() :返回一个值为该字符串的字符串,这将删除字符串末尾的所有空格。
您最有可能看一下strip()并问:“这与现有的trim()方法有何不同?” 答案在于空间定义的差异。 ( 译者注:简而言之, strip()更好地理解了Unicode, 并在StackOverflow上进行了详细的分析 )
java.lang.StringBuffer
java.lang.StringBuilder
这两个类都有一个新的compareTo()方法,该方法采用StringBuffer / StringBuilder并返回一个int。 词法比较方法类似于CharSequence中新的compareTo()方法。
java.lang.Thread
没有新方法。 删除()和停止(Throwable)方法已被删除。 仍然存在不带任何参数的stop()方法。 可能导致兼容性问题。
java.nio.ByteBuffer
java.nio.CharBuffer
java.nio.DoubleBuffer
java.nio.FloatBuffer
java.nio.LongBuffer
java.nio.ShortBuffer
现在,所有这些类都具有mismatch()方法,该方法查找并返回此缓冲区与传递的缓冲区之间的第一个不匹配项的相对索引。
java.nio.channels.SelectionKey
- int interestOpsAnd(int) :以原子方式将此键的权益(键的权益)设置为现有权益和传递的值的按位相交(“和”)。
- int interestOpsOr(int) :以原子方式设置此密钥的利益(密钥的利益)为现有利益和传递的值的按位并集(“或”)。
java.nio.channels.Selector
- int select(java.util.function.Consumer,long) :选择键并对其相应的通道准备进行I / O操作的键执行操作。 长参数是超时。
- int select(java.util.function.Consumer) :与上面相同,但没有超时。
- int selectNow(java.util.function.Consumer) :与上面相同,只是非阻塞。
java.nio.file.Files
- String readString(Path) :将文件中的所有内容读取为字符串,然后使用UTF-8编码从字节解码为字符。
- 字符串readString(路径,字符集) :如上所述,区别在于使用指定的字符集进行从字节到字符的解码。
- 路径writeString(路径,CharSequence,java.nio.file.OpenOption []) :将CharSequence写入文件。 使用UTF-8编码将字符编码为字节。
- 路径writeString(Path,CharSequence,java.nio.file.Charset,OpenOption []) :与上面相同,使用Charset中指定的编码将字符编码为字节。
java.nio.file.Path
- (String,String [])的 Path:从路径的字符串参数或字符串序列返回的Path,这些字符串或字符串序列组合后会形成路径字符串。
- (net.URI)的路径:从URI返回路径。
java.util.Collection
- Object [] toArray(java.util.function.IntFunction) :使用提供的生成函数分配返回的数组,返回一个包含此集合中所有元素的数组。
java.util.concurrent.PriorityBlockingQueue
java.util.PriorityQueue
- void forEach(java.util.function.Consumer) :对每个Iterable元素执行传递的操作,直到处理完所有元素或该操作引发异常为止。
- boolean removeAll(java.util.Collection) :删除此集合中也包含在指定集合中的所有元素(可选操作)。
- boolean removeIf(java.util.function.Predicate) :从此集合中移除所有满足给定谓词的元素。
- boolean keepAll(java.util.Collection) :仅保存此集合中包含在传输的集合中的那些元素(可选操作)。
java.util.concurrent.TimeUnit
- long convert(java.time.Duration) :将传递的Duration转换为此类型。
java.util.function.Predicate
- 谓词not(谓词) :返回谓词,它是所传输谓词的否定。
这是JDK 11中我最喜欢的新API之一。例如,您可以转换以下代码:
lines.stream() .filter(s -> !s.isBlank())
在
lines.stream() .filter(Predicate.not(String::isBlank))
或者如果我们使用静态导入:
lines.stream() .filter(not(String::isBlank))
我个人认为此版本更易于理解和简洁。
java.util.Optional
java.util.OptionalInt
java.util.OptionalDouble
java.util.OptionalLong
- boolean isEmpty() :如果没有值,则返回true,否则返回false。
java.util.regex.Pattern
- Predicate asMatchPredicate() :我认为这可能是新JDK 11 API的瑰宝。创建一个谓词,检查该模板是否与给定的输入字符串匹配。
java.util.zip.Deflater
int deflate(ByteBuffer) :压缩输入并用它填充指定的缓冲区。
int deflate(ByteBuffer,int) :压缩输入并用它填充指定的缓冲区。 返回实际的压缩数据量。
setDictionary(ByteBuffer) :将指定的压缩字典设置为此缓冲区中的字节。 这是ByteBuffer现在可以接受的现有方法的重载形式,而不是字节数组。
setInput(ByteBuffer) :设置要压缩的输入。 也是现有方法的重载形式。
java.util.zip.Inflater
- int inflate(ByteBuffer) :将字节解压缩到指定的缓冲区。 返回实际的未压缩字节数。
- setDictionary(ByteBuffer) :将指定的字典设置为此缓冲区中的字节。 现有方法的重载形式。
- setInput(ByteBuffer) :设置用于解压缩的输入。 现有方法的重载形式。
javax.print.attribute.standard.DialogOwner
这是JDK 11中的新类。用于支持打印对话框或页面设置的请求。 必须显示在所有窗口或特定窗口的顶部。
javax.swing.DefaultComboBoxModel
javax.swing.DefaultListModel
- void addAll(Collection) :添加集合中存在的所有元素。
- void addAll(int,Collection) :从指定的索引开始,添加集合中存在的所有元素。
javax.swing.ListSelectionModel
- int [] getSelectedIndices() :按升序返回所选模型中所有所选索引的数组。
- int getSelectedItemsCount() :返回所选项目的数量。
jdk.jshell.EvalException
- jshell.JShellException getCause() :在由EvalException表示的执行客户端中返回可引发的原因包装器;如果原因不存在或未知,则返回null。
新功能(不是公共API)
JEP 181:基于嵌套的访问控制
Java(和其他语言)通过内部类支持嵌套类。 为了进行正确的操作,编译器必须执行一些技巧。 例如:
public class Outer { private int outerInt; class Inner { public void printOuterInt() { System.out.println("Outer int = " + outerInt); } } }
在进行编译之前,编译器会对此进行修改以创建如下所示的内容:
public class Outer { private int outerInt; public int access$000() { return outerInt; } }
class Inner$Outer { Outer outer; public void printOuterInt() { System.out.println("Outer int = " + outer.access$000()); } }
尽管从逻辑上讲,内部类与外部类是同一代码的一部分,但它被编译为单独的类。 因此,这需要合成方法(“桥”),该方法必须由编译器创建以提供对外部类的私有字段的访问。
该JEP表示“套接字”的概念,其中同一套接字的两个成员(在我们的示例中为“外部”和“内部”)是邻居。 * .class文件格式添加了两个新属性:NestHost和NestMembers。 这些更改对于其他支持嵌套类的字节码编译语言也很有用。
此功能为java.lang.Class提供了三种新方法:
- 类getNestHost()
- 类别[] getNestMembers()
- boolean isNestmateOf(clazz)
此功能还需要更改Java虚拟机规范(JVMS) ,尤其是在5.4.4节“访问控制”中。
JEP 309:动态类文件常量
该JEP描述了* .class文件格式的扩展,以使用常量池CONSTANT_Dynamic(在演示文稿中通常称为condy)来支持新格式。 动态常数的想法似乎是矛盾的,但是实际上,您可以将其视为Java中的最终值。 常量池的值未在编译阶段设置(与其他常量不同),但是引导程序方法用于在运行时确定该值。 因此,该值是动态的,但是由于其值仅设置一次,因此它也是恒定的。
对于正在开发新语言和编译器的人来说,此功能将非常有用。 谁将生成字节码和* .class文件以在JVM上运行。 这将简化某些任务。
此功能提供了一个带有九个新方法的新类java.lang.invoke.ConstantBootstraps。 我不会在这里列出所有内容; 这些是用于动态计算常量的引导方法。
此功能需要对JVMS进行更改,特别是在特殊调用字节代码和“常量池”的4.4节的使用方式方面。
JEP 315:改进Aarch64本征
这是Red Hat提供的JEP。 JVM现在可以使用Arm 64命令集中的更多专用指令,尤其是可以改善java.lang.Math类的sin(),cos()和log()方法的操作。
JEP 318:Epsilon垃圾收集器
红帽也为此JEP做出了贡献。 Epsilon垃圾收集器有些不寻常,因为它不收集垃圾! 创建新对象时,如有必要,它将分配新的内存,但是不会释放没有链接的对象所占用的空间。
那么,看起来有什么意义呢? 至少有两个用途:
- 首先,此收集器旨在确保评估新的GC算法对性能的影响。 想法是使用Epsilon GC运行示例应用程序并生成度量。 包括新的GC算法,运行相同的测试,并比较结果。
- 对于非常短暂或短暂的任务(例如云中的无服务器功能),可以确保不超出分配给堆空间的内存。 通过消除应用程序代码中的开销(包括收集决定是否运行收集器所需的统计信息),可以提高性能。
如果堆空间已用完,则可以通过以下三种方式之一配置后续的JVM操作:
- 调用常规的OutOfMemoryError。
- 重置堆
- 硬停止JVM并可能执行外部任务(例如,启动调试器)。
JEP 324:与Curve25519和Curve448的关键协议
密码标准正在不断变化和提高。 在这种情况下,将现有的具有椭圆曲线的Diffie-Hellman方案替换为Curve25519和Curve448。 这是RFC-7748中定义的关键协议方案。
JEP 327:Unicode 10
Java平台支持Unicode以启用所有字符集的处理。 由于Unicode已更新为版本10 ,因此JDK也已更新为支持该版本的标准。
我总是很高兴看到新版本中包含哪些Unicode开发人员。 Unicode 10具有8,518个新字符。 其中包括比特币符号,Nüshu字符集(中国妇女用来写诗)以及Soyombo和Zanabazar Square(在佛教历史文献中用于书写梵语,藏语和蒙古语的字符)。 还添加了许多其他表情符号,包括期待已久(显然)的科尔伯特表情符号 。
请记住,从JDK 9开始,您可以在属性文件(.properties)中使用UTF-8。 这意味着在此类文件中可以使用任何Unicode字符。 包括表情符号。 还是Nüshu。
JEP 328:飞行记录器
Flight Recorder — JVM. JDK 11 Oracle JDK. , Oracle Oracle JDK OpenJDK, OpenJDK.
JEP :
: jdk.jfr jdk.management.jfr.
JEP 329: ChaCha20 and Poly1305 Cryptographic Algorithms
JEP 324, , JDK. ChaCha20 ChaCha20-Poly1305, RFC 7539. ChaCha20 — , , RC4.
JEP 331: Low-overhead Heap Profiling
, JEP, Google. Java JVM.
:
JEP 332: Transport Layer Security (TLS) 1.3
TLS 1.3 (RFC 8446) " " TLS . JDK , Datagram Transport Layer Security (DTLS).
JEP 333: ZGC A Scalable, Low Latency Garbage Collector
, , () . ( , Weak Generational Hypothesis ) ( ) GC . "" , . .
ZGC — region-based ( G1), NUMA aware compacting . .
pauseless , C4 Zing JVM.
JEP 335: Deprecate the Nashorn Scripting Engine
Nashorn JDK 8 Rhino Javascript . , Nashorn API jjs Java. , . Graal VM , , .
JEP 336: Deprecate the Pack200 Tools and APIs
Pack200 — JAR-, Java SE 5.0. JPMS JDK 9 Pack200 JDK. pack200 unpack200 API Pack200 java.util.jar JDK. , .
结论
JDK 11 — LTS JDK ( ). , , , , JVM , .
Zulu JDK 11 !
JDK 11?
( . : , )