Java 9 - 快速指南
Java 9 - Overview
JAVA 9(又名jdk 1.9)是JAVA编程语言开发的主要版本。 它的初始版本于2017年9月21日发布.Java 9发布的主要目标是 -
为了使JDK和Java Standard Edition平台模块化,它可以很好地降低到小型计算设备。
提高JDK和Java实现的整体安全性。
为JAVA SE和EE平台轻松构建java代码库和大型应用程序的构建过程和维护。
设计和实现Java平台的标准模块系统,可以轻松地应用于Platform和JDK。
新功能 (New Features)
Java 8中增加了90多个增强功能,最重要的增强功能如下所述 -
Module - 作为模块引入的一种新型Java编程组件,它是一个命名的,自描述的代码和数据集合。
REPL (JShell) - 添加到Java平台的Read-Eval-Print Loop(REPL)功能。
HTTP 2 Client - 支持websockets和HTTP 2流以及服务器推送功能的新HTTPClient API。
Improved JavaDocs - 支持HTML5输出生成。 为生成的API文档提供搜索框。
Multirelease JAR - 增强JAR格式,以便多个Java发行版特定版本的类文件可以共存于一个存档中。
Collection Factory Methods - 用于创建这些集合的不可变实例的List,Set和Map接口的新静态工厂方法。
Private Interface Methods - 增强了私有和私有静态方法的接口。
Process API Improvements - 改进的API来控制和管理操作系统流程。
Stream API Improvements - 通过允许过滤对象序列化数据的传入流来增强安全性和健壮性。
Try With Resources improvement - 现在,最终变量可以用作try-with-resources语句中的资源。
Enhanced @Deprecated Annotation - 更新了@Deprecated注释,以提供有关API状态和预期处置的更多信息。
Inner Class Diamond Operator - 如果可以表示推断类型的参数类型,则允许菱形操作符与匿名类一起使用。
Optional Class Improvements - 向java.util.Optional类添加了新的有用方法。
Multiresolution Image API - 支持将具有不同分辨率的一组图像封装到单个多分辨率图像中。
CompletableFuture API improvements - 当进程使用ProcessHandle.onExit方法退出时,CompletableFuture类的异步机制可以执行操作。
Lightweight JSON - 一种轻量级API,用于在java 9中通过json使用和生成文档和数据流。
Reactive Streams API - Java SE 9中引入了一个新的Reactive Streams API,以支持Java 9中的反应式编程。
Java 9 - Environment Setup
本地环境设置 (Local Environment Setup)
如果要为Java编程语言设置自己的环境,那么本节将指导您完成整个过程。 请按照以下步骤设置Java环境。
Java SE可免费下载。 要下载,请单击此处 ,下载与您的操作系统兼容的版本。
按照说明下载Java,然后运行.exe在您的计算机上安装Java。 在计算机上安装Java后,需要设置环境变量以指向正确的安装目录。
设置Windows 2000/XP的路径
假设您已在c:\Program Files\java\jdk目录中安装了Java -
右键单击“我的电脑”,然后选择“属性”。
单击“高级”选项卡下的“环境变量”按钮。
现在,编辑'Path'变量并在其末尾添加Java可执行文件目录的路径。 例如,如果路径当前设置为C:\Windows\System32 ,则按以下方式编辑它
C:\Windows\System32;c:\Program Files\java\jdk\bin
设置Windows 95/98/ME的路径
假设您已在c:\Program Files\java\jdk目录中安装了Java -
编辑'C:\autoexec.bat'文件并在结尾添加以下行 -
SET PATH = %PATH%;C:\Program Files\java\jdk\bin
设置Linux,UNIX,Solaris,FreeBSD的路径
应将环境变量PATH设置为指向已安装Java二进制文件的位置。 如果您在执行此操作时遇到问题,请参阅您的shell文档。
例如,如果您使用bash作为shell,那么您将在.bashrc的末尾添加以下行 -
export PATH = /path/to/java:$PATH'
流行的Java编辑器 (Popular Java Editors)
要编写Java程序,您需要一个文本编辑器。 市场上还有更复杂的IDE。 下面简要介绍最受欢迎的 -
Notepad - 在Windows机器上,您可以使用任何简单的文本编辑器,如记事本(本教程推荐)或写字板。 Notepad ++也是一个增强功能的自由文本编辑器。
Netbeans - 它是一个开源和免费的Java IDE,可以从https://www.netbeans.org/index.html下载。
Eclipse - 它也是由Eclipse开源社区开发的Java IDE,可以从https://www.eclipse.org/下载。
IDE或集成开发环境,提供所有常用工具和工具以帮助编程,例如源代码编辑器,构建工具和调试器等。
Java 9 - Module System
Java 9是一种称为模块的新型编程组件。 模块是代码和数据的自描述集合,并具有用于标识它的名称。
特点 (Features)
使用Modules组件,Java 9中添加了以下增强功能 -
引入了新的可选阶段,链接时间。 此阶段介于编译时和运行时之间。 在此阶段,可以组装和优化一组模块,使用jlink工具制作自定义运行时映像。
javac,jlink和java有其他选项来指定模块路径,这些选项进一步定位了模块的定义。
JAR格式更新为模块化JAR,其根目录中包含module-info.class文件。
引入了JMOD格式,一种打包格式(类似于JAR),可以包含本机代码和配置文件。
创建模块
按照创建模块的步骤说com.iowiki.greetings。
Step 1
创建一个文件夹C:\> JAVA\src。 现在创建一个com.iowiki.greetings文件夹,它与我们正在创建的模块名称相同。
Step 2
使用以下代码在C:\> JAVA\src\com.iowiki.greetings文件夹中创建module-info.java。
module-info.java
module com.iowiki.greetings { }
module-info.java是用于创建模块的文件。 在这一步中,我们创建了一个名为com.iowiki.greetings的模块。 按照惯例,此文件应驻留在名称与模块名称相同的文件夹中。
Step 3
在模块中添加源代码。 使用以下代码在C:\> JAVA\src\com.iowiki.greetings\com\iowiki\greetings文件夹中创建Java9Tester.java。
Java9Tester.java
package com.iowiki.greetings;
public class Java9Tester {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
按照惯例,模块的源代码位于同一目录中,即模块的名称。
Step 4
创建一个文件夹C:\> JAVA\mods。 现在创建一个com.iowiki.greetings文件夹,它与我们创建的模块名称相同。 现在将模块编译为mods目录。
C:/ > JAVA > javac -d mods/com.iowiki.greetings
src/com.iowiki.greetings/module-info.java
src/com.iowiki.greetings/com/iowiki/greetings/Java9Tester.java
Step 5
让我们运行模块来查看结果。 运行以下命令。
C:/ > JAVA > java --module-path mods -m com.iowiki.greetings/com.iowiki.greetings.Java9Tester
这里module-path将模块位置提供为mods,-m表示主模块。
输出 (Output)
它将在控制台上打印以下输出。
Hello World!
Java 9 - REPL (JShell)
REPL代表Read-Eval-Print Loop。 使用JShell,java具有REPL功能。 使用REPL,我们可以编写和测试基于java的逻辑,无需使用javac进行编译,直接查看计算结果。
运行JShell
打开命令提示符并键入jshell。
$ jshell
| Welcome to JShell -- Version 9-ea
| For an introduction type: /help intro
jshell>
Viewing JShell commands
一旦jshell命令开始运行,输入/ help。
jshell> /help
| Type a Java language expression, statement, or declaration.
| Or type one of the following commands:
| /list [<name or id>|-all|-start]
| list the source you have typed
| /edit <name or id>
| edit a source entry referenced by name or id
| /drop <name or id>
| delete a source entry referenced by name or id
| /save [-all|-history|-start] <file>
| Save snippet source to a file.
| /open <file>
| open a file as source input
| /vars [<name or id>|-all|-start]
| list the declared variables and their values
| /methods [<name or id>|-all|-start]
| list the declared methods and their signatures
| /types [<name or id>|-all|-start]
| list the declared types
| /imports
| list the imported items
Running JShell command
一旦jshell命令开始运行就输入/ import,并查看使用的导入。
jshell> /imports
| import java.io.*
| import java.math.*
| import java.net.*
| import java.nio.file.*
| import java.util.*
| import java.util.concurrent.*
| import java.util.function.*
| import java.util.prefs.*
| import java.util.regex.*
| import java.util.stream.*
jshell>
在JShell中运行计算。
尝试在JShell中运行简单的计算。
jshell> 3+1
$1 ==> 4
jshell> 13%7
$2 ==> 6
jshell> $2
$2 ==> 6
jshell>
在JShell中创建和使用函数
创建一个doubled()函数来获取int并返回其doubled值。
jshell> int doubled(int i){ return i*2;}
| created method doubled(int)
jshell> doubled(6)
$3 ==> 12
jshell>
退出JShell
输入/退出。
jshell> /exit
| Goodbye
Java 9 - Improved JavaDocs
可以使用javadoc工具生成Java文档。 它目前以html 4.0格式生成文档。 在java 9中,我们可以在命令行参数中使用-html5选项生成html 5格式的文档。
旧样式java文档
请考虑C:/ JAVA文件夹中的以下代码。
Tester.java
/**
* @author MahKumar
* @version 0.1
*/
public class Tester {
/**
* Default method to be run to print
* <p>Hello world</p>
* @param args command line arguments
*/
public static void main(String []args) {
System.out.println("Hello World");
}
}
现在运行jdk 7的javadoc工具来生成文档。
C:\JAVA>javadoc -d C:/JAVA Tester.java
Loading source file tester.java...
Constructing Javadoc information...
Standard Doclet version 1.7.0_21
Building tree for all the packages and classes...
Generating C:\JAVA\Tester.html...
Generating C:\JAVA\package-frame.html...
Generating C:\JAVA\package-summary.html...
Generating C:\JAVA\package-tree.html...
Generating C:\JAVA\constant-values.html...
Building index for all the packages and classes...
Generating C:\JAVA\overview-tree.html...
Generating C:\JAVA\index-all.html...
Generating C:\JAVA\deprecated-list.html...
Building index for all classes...
Generating C:\JAVA\allclasses-frame.html...
Generating C:\JAVA\allclasses-noframe.html...
Generating C:\JAVA\index.html...
Generating C:\JAVA\help-doc.html...
它将在C:/ JAVA目录中创建java文档页面,您将看到以下输出。
支持搜索和HTML5的新Java文档
使用-html5标志运行jdk 9的javadoc工具以生成新类型的文档。
C:\JAVA> javadoc -d C:/JAVA -html5 Tester.java
Loading source file Tester.java...
Constructing Javadoc information...
Standard Doclet version 9.0.1
Building tree for all the packages and classes...
Generating C:\JAVA\Tester.html...
Generating C:\JAVA\package-frame.html...
Generating C:\JAVA\package-summary.html...
Generating C:\JAVA\package-tree.html...
Generating C:\JAVA\constant-values.html...
Building index for all the packages and classes...
Generating C:\JAVA\overview-tree.html...
Generating C:\JAVA\index-all.html...
Generating C:\JAVA\deprecated-list.html...
Building index for all classes...
Generating C:\JAVA\allclasses-frame.html...
Generating C:\JAVA\allclasses-frame.html...
Generating C:\JAVA\allclasses-noframe.html...
Generating C:\JAVA\allclasses-noframe.html...
Generating C:\JAVA\index.html...
Generating C:\JAVA\help-doc.html...
它将在D:/ test目录中创建更新的java文档页面,您将看到以下输出。
Java 9 - Multirelease JAR
在java 9中,引入了一个新特性,其中增强了jar格式以具有不同版本的java类,或者可以根据平台维护和使用资源。 在JAR中,文件MANIFEST.MF文件的主要部分中有一个条目Multi-Release:true。 META-INF目录还包含一个versions子目录,其子目录(从9开始,用于Java 9)存储特定于版本的类和资源文件。
在这个例子中,我们将使用多版本jar有两个版本的Tester.java文件,一个用于jdk 7,另一个用于jdk 9,并在不同的jdk版本上运行。
Steps
Step 1 - 创建文件夹c:/ test/java7/com/iowiki。 使用以下内容创建Test.java -
Tester.java
package com.iowiki;
public class Tester {
public static void main(String[] args) {
System.out.println("Inside java 7");
}
}
Step 2 - 创建文件夹c:/ test/java9/com/iowiki。 使用以下内容创建Test.java -
Tester.java
package com.iowiki;
public class Tester {
public static void main(String[] args) {
System.out.println("Inside java 9");
}
}
编译源代码。
C:\test > javac --release 9 java9/com/iowiki/Tester.java
C:\JAVA > javac --release 7 java7/com/iowiki/Tester.java
创建多版本jar
C:\JAVA > jar -c -f test.jar -C java7 . --release 9 -C java9.
Warning: entry META-INF/versions/9/com/iowiki/Tester.java,
multiple resources with same name
使用JDK 7运行
C:\JAVA > java -cp test.jar com.iowiki.Tester
Inside Java 7
使用JDK 9运行
C:\JAVA > java -cp test.jar com.iowiki.Tester
Inside Java 9
Java 9 - Collection Factory Methods
使用Java 9,新的工厂方法被添加到List,Set和Map接口以创建不可变实例。 这些工厂方法是便利工厂方法,以较简洁和简洁的方式创建集合。
创建集合的旧方法
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Tester {
public static void main(String []args) {
Set<String> set = new HashSet<>();
set.add("A");
set.add("B");
set.add("C");
set = Collections.unmodifiableSet(set);
System.out.println(set);
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list = Collections.unmodifiableList(list);
System.out.println(list);
Map<String, String> map = new HashMap<>();
map.put("A","Apple");
map.put("B","Boy");
map.put("C","Cat");
map = Collections.unmodifiableMap(map);
System.out.println(map);
}
}
输出 (Output)
它将打印以下输出。
[A, B, C]
[A, B, C]
{A=Apple, B=Boy, C=Cat}
新方法
使用java 9,以下方法将添加到List,Set和Map接口以及它们的重载对应物。
static <E> List<E> of(E e1, E e2, E e3);
static <E> Set<E> of(E e1, E e2, E e3);
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3);
static <K,V> Map<K,V> ofEntries(Map.Entry<? extends K,? extends V>... entries)
注意事项 (Points to Note)
对于List和Set接口,(...)方法被重载为0到10个参数,一个带有var args参数。
对于Map接口,(...)方法重载为0到10个参数。
如果Map接口的参数超过10个,则可以使用ofEntries(...)方法接受var args参数。
创建集合的新方法
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.AbstractMap;
import java.util.Map;
import java.util.Set;
public class Tester {
public static void main(String []args) {
Set<String> set = Set.of("A", "B", "C");
System.out.println(set);
List<String> list = List.of("A", "B", "C");
System.out.println(list);
Map<String, String> map = Map.of("A","Apple","B","Boy","C","Cat");
System.out.println(map);
Map<String, String> map1 = Map.ofEntries (
new AbstractMap.SimpleEntry<>("A","Apple"),
new AbstractMap.SimpleEntry<>("B","Boy"),
new AbstractMap.SimpleEntry<>("C","Cat"));
System.out.println(map1);
}
}
输出 (Output)
它将打印以下输出。
[A, B, C]
[A, B, C]
{A=Apple, B=Boy, C=Cat}
{A=Apple, B=Boy, C=Cat}
Java 9 - Private Interface Methods
在Java 8之前,接口可以具有以下类型的变量/方法。
- 常数变量
- 抽象方法
因此,我们不能在接口中使用方法实现,或者更准确地说是Java 8之前的默认实现。请参阅示例。
public class Tester {
public static void main(String []args) {
LogOracle log = new LogOracle();
log.logInfo("");
log.logWarn("");
log.logError("");
log.logFatal("");
LogMySql log1 = new LogMySql();
log1.logInfo("");
log1.logWarn("");
log1.logError("");
log1.logFatal("");
}
}
final class LogOracle implements Logging {
@Override
public void logInfo(String message) {
getConnection();
System.out.println("Log Message : " + "INFO");
closeConnection();
}
@Override
public void logWarn(String message) {
getConnection();
System.out.println("Log Message : " + "WARN");
closeConnection();
}
@Override
public void logError(String message) {
getConnection();
System.out.println("Log Message : " + "ERROR");
closeConnection();
}
@Override
public void logFatal(String message) {
getConnection();
System.out.println("Log Message : " + "FATAL");
closeConnection();
}
@Override
public void getConnection() {
System.out.println("Open Database connection");
}
@Override
public void closeConnection() {
System.out.println("Close Database connection");
}
}
final class LogMySql implements Logging {
@Override
public void logInfo(String message) {
getConnection();
System.out.println("Log Message : " + "INFO");
closeConnection();
}
@Override
public void logWarn(String message) {
getConnection();
System.out.println("Log Message : " + "WARN");
closeConnection();
}
@Override
public void logError(String message) {
getConnection();
System.out.println("Log Message : " + "ERROR");
closeConnection();
}
@Override
public void logFatal(String message) {
getConnection();
System.out.println("Log Message : " + "FATAL");
closeConnection();
}
@Override
public void getConnection() {
System.out.println("Open Database connection");
}
@Override
public void closeConnection() {
System.out.println("Close Database connection");
}
}
interface Logging {
String ORACLE = "Oracle_Database";
String MYSQL = "MySql_Database";
void logInfo(String message);
void logWarn(String message);
void logError(String message);
void logFatal(String message);
void getConnection();
void closeConnection();
}
输出 (Output)
您将看到以下输出。
Open Database connection
Log Message : INFO
Close Database connection
Open Database connection
Log Message : WARN
Close Database connection
Open Database connection
Log Message : ERROR
Close Database connection
Open Database connection
Log Message : FATAL
Close Database connection
在上面的示例中,每个日志方法都有自己的实现。 使用Java 8接口可以具有以下类型的变量/方法。
- 常数变量
- 抽象方法
- 默认方法
- 静态方法
让我们使用Java 8在接口本身中使用默认实现和静态方法。
public class Tester {
public static void main(String []args) {
LogOracle log = new LogOracle();
log.logInfo("");
log.logWarn("");
log.logError("");
log.logFatal("");
LogMySql log1 = new LogMySql();
log1.logInfo("");
log1.logWarn("");
log1.logError("");
log1.logFatal("");
}
}
final class LogOracle implements Logging {
}
final class LogMySql implements Logging {
}
interface Logging {
String ORACLE = "Oracle_Database";
String MYSQL = "MySql_Database";
default void logInfo(String message) {
getConnection();
System.out.println("Log Message : " + "INFO");
closeConnection();
}
default void logWarn(String message) {
getConnection();
System.out.println("Log Message : " + "WARN");
closeConnection();
}
default void logError(String message) {
getConnection();
System.out.println("Log Message : " + "ERROR");
closeConnection();
}
default void logFatal(String message) {
getConnection();
System.out.println("Log Message : " + "FATAL");
closeConnection();
}
static void getConnection() {
System.out.println("Open Database connection");
}
static void closeConnection() {
System.out.println("Close Database connection");
}
}
输出 (Output)
您将看到以下输出。
Open Database connection
Log Message : INFO
Close Database connection
Open Database connection
Log Message : WARN
Close Database connection
Open Database connection
Log Message : ERROR
Close Database connection
Open Database connection
Log Message : FATAL
Close Database connection
在上面的例子中,我们再次重复。 使用Java 9接口可以具有以下类型的变量/方法。
- 常数变量
- 抽象方法
- 默认方法
- 静态方法
- Private methods
- Private Static methods
让我们拥有私有方法并在Java 9中使用它们。
public class Tester {
public static void main(String []args) {
LogOracle log = new LogOracle();
log.logInfo("");
log.logWarn("");
log.logError("");
log.logFatal("");
LogMySql log1 = new LogMySql();
log1.logInfo("");
log1.logWarn("");
log1.logError("");
log1.logFatal("");
}
}
final class LogOracle implements Logging {
}
final class LogMySql implements Logging {
}
interface Logging {
String ORACLE = "Oracle_Database";
String MYSQL = "MySql_Database";
private void log(String message, String prefix) {
getConnection();
System.out.println("Log Message : " + prefix);
closeConnection();
}
default void logInfo(String message) {
log(message, "INFO");
}
default void logWarn(String message) {
log(message, "WARN");
}
default void logError(String message) {
log(message, "ERROR");
}
default void logFatal(String message) {
log(message, "FATAL");
}
private static void getConnection() {
System.out.println("Open Database connection");
}
private static void closeConnection() {
System.out.println("Close Database connection");
}
}
输出 (Output)
您将看到以下输出。
Open Database connection
Log Message : INFO
Close Database connection
Open Database connection
Log Message : WARN
Close Database connection
Open Database connection
Log Message : ERROR
Close Database connection
Open Database connection
Log Message : FATAL
Close Database connection
Java 9 - Process API Improvements
在Java 9中,负责控制和管理操作系统进程的Process API得到了显着改进。 ProcessHandle类现在提供进程的本机进程ID,开始时间,累计CPU时间,参数,命令,用户,父进程和后代。 ProcessHandle类还提供了检查进程活跃性和破坏进程的方法。 它具有onExit方法,CompletableFuture类可以在进程退出时异步执行操作。
Tester.java
import java.time.ZoneId;
import java.util.stream.Stream;
import java.util.stream.Collectors;
import java.io.IOException;
public class Tester {
public static void main(String[] args) throws IOException {
ProcessBuilder pb = new ProcessBuilder("notepad.exe");
String np = "Not Present";
Process p = pb.start();
ProcessHandle.Info info = p.info();
System.out.printf("Process ID : %s%n", p.pid());
System.out.printf("Command name : %s%n", info.command().orElse(np));
System.out.printf("Command line : %s%n", info.commandLine().orElse(np));
System.out.printf("Start time: %s%n",
info.startInstant().map(i -> i.atZone(ZoneId.systemDefault())
.toLocalDateTime().toString()).orElse(np));
System.out.printf("Arguments : %s%n",
info.arguments().map(a -> Stream.of(a).collect(
Collectors.joining(" "))).orElse(np));
System.out.printf("User : %s%n", info.user().orElse(np));
}
}
输出 (Output)
您将看到以下输出。
Process ID : 5800
Command name : C:\Windows\System32\notepad.exe
Command line : Not Present
Start time: 2017-11-04T21:35:03.626
Arguments : Not Present
User: administrator
Java 9 - Stream API Improvements
Streams是在Java中引入的,以帮助开发人员从一系列对象中执行聚合操作。 使用Java 9,几乎没有更多方法可以使流更好。
takeWhile(Predicate Interface)
语法 (Syntax)
default Stream<T> takeWhile(Predicate<? super T> predicate)
takeWhile方法获取所有值,直到谓词返回false。 在有序流的情况下,它返回一个流,该流由从该流中获取的与给定谓词匹配的元素的最长前缀组成。
例子 (Example)
import java.util.stream.Stream;
public class Tester {
public static void main(String[] args) {
Stream.of("a","b","c","","e","f").takeWhile(s->!s.isEmpty())
.forEach(System.out::print);
}
}
输出 (Output)
takeWhile方法获取所有a,b和c值,然后一旦string为空,它就停止执行。
abc
dropWhile(Predicate Interface)
语法 (Syntax)
default Stream<T> dropWhile(Predicate<? super T> predicate)
dropWhile方法在开始时抛弃所有值,直到谓词返回true。 在有序流的情况下,在丢弃与给定谓词匹配的元素的最长前缀之后,它返回由该流的剩余元素组成的流。
例子 (Example)
import java.util.stream.Stream;
public class Tester {
public static void main(String[] args) {
Stream.of("a","b","c","","e","f").dropWhile(s-> !s.isEmpty())
.forEach(System.out::print);
System.out.println();
Stream.of("a","b","c","","e","","f").dropWhile(s-> !s.isEmpty())
.forEach(System.out::print);
}
}
输出 (Output)
dropWhile方法删除a,b和c值,然后一旦string为空,它将获取所有值。
ef
ef
iterate
语法 (Syntax)
static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
iterate方法现在有hasNext谓词作为参数,一旦hasNext谓词返回false就停止循环。
例子 (Example)
import java.util.stream.IntStream;
public class Tester {
public static void main(String[] args) {
IntStream.iterate(3, x -> x < 10, x -> x+ 3).forEach(System.out::println);
}
}
输出 (Output)
3
6
9
ofNullable
语法 (Syntax)
static <T> Stream<T> ofNullable(T t)
引入了ofNullable方法来防止NullPointerExceptions并避免对流进行空检查。 此方法返回包含单个元素的顺序Stream(如果为非null),否则返回空Stream。
例子 (Example)
import java.util.stream.Stream;
public class Tester {
public static void main(String[] args) {
long count = Stream.ofNullable(100).count();
System.out.println(count);
count = Stream.ofNullable(null).count();
System.out.println(count);
}
}
输出 (Output)
1
0
Java 9 - Try With Resources improvement
try-with-resources语句是一个try语句,其中包含一个或多个正式声明的资源。 这里资源是一个对象,一旦不再需要就应该关闭它。 try-with-resources语句确保在需求完成后关闭每个资源。 任何实现java.lang.AutoCloseable或java.io.Closeable的对象,接口都可以用作资源。
在Java 9之前,资源将在try之前或try语句内部声明,如下面给出的示例所示。 在这个例子中,我们将使用BufferedReader作为资源来读取字符串,然后关闭BufferedReader。
Tester.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
public class Tester {
public static void main(String[] args) throws IOException {
System.out.println(readData("test"));
}
static String readData(String message) throws IOException {
Reader inputString = new StringReader(message);
BufferedReader br = new BufferedReader(inputString);
try (BufferedReader br1 = br) {
return br1.readLine();
}
}
}
输出 (Output)
test
在这里,我们需要在try statment中声明资源br1然后使用它。 在Java9中,我们不再需要声明br1,并且在程序之后将给出相同的结果。
Tester.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
public class Tester {
public static void main(String[] args) throws IOException {
System.out.println(readData("test"));
}
static String readData(String message) throws IOException {
Reader inputString = new StringReader(message);
BufferedReader br = new BufferedReader(inputString);
try (br) {
return br.readLine();
}
}
}
输出 (Output)
test
Java 9 - Enhanced @Deprecated Annotation
@Deprecated注释是在java 5版本中引入的。 用@Deprecated注释的程序元素意味着它不应该被用于以下任何原因 -
- 它的使用可能会导致错误。
- 在将来的版本中可能不兼容。
- 它可能会在将来的版本中删除。
- 一个更好,更有效的替代方案取代了它。
每当使用不推荐使用的元素时,编译器都会生成警告。 使用Java 9,对@Deprecated注释进行了两项新的增强。
forRemoval - 指示在将来的版本中是否要删除带注释的元素。 默认值为false。
since - 返回已注释元素已弃用的版本。 默认值为空字符串。
从此贬低
以下Java 9上的布尔类javadoc示例说明了在@Deprecated注释中使用since属性。
用forRemoval弃用
以下是Java 9上的System类javadoc的示例,说明了对@Deprecated注释使用forRemoval属性。
Java 9 - Inner Class Diamond Operator
在java 7中引入了Diamond运算符,使代码更具可读性,但它不能与Anonymous内部类一起使用。 在java 9中,它也可以与匿名类一起使用,以简化代码并提高可读性。 在Java 9之前考虑以下代码。
Tester.java
public class Tester {
public static void main(String[] args) {
Handler<Integer> intHandler = new Handler<Integer>(1) {
@Override
public void handle() {
System.out.println(content);
}
};
intHandler.handle();
Handler<? extends Number> intHandler1 = new Handler<Number>(2) {
@Override
public void handle() {
System.out.println(content);
}
};
intHandler1.handle();
Handler<?> handler = new Handler<Object>("test") {
@Override
public void handle() {
System.out.println(content);
}
};
handler.handle();
}
}
abstract class Handler<T> {
public T content;
public Handler(T content) {
this.content = content;
}
abstract void handle();
}
输出 (Output)
1
2
Test
使用Java 9,我们可以将<>运算符与匿名类一起使用,如下所示。
Tester.java
public class Tester {
public static void main(String[] args) {
Handler<Integer> intHandler = new Handler<>(1) {
@Override
public void handle() {
System.out.println(content);
}
};
intHandler.handle();
Handler<? extends Number> intHandler1 = new Handler<>(2) {
@Override
public void handle() {
System.out.println(content);
}
};
intHandler1.handle();
Handler<?> handler = new Handler<>("test") {
@Override
public void handle() {
System.out.println(content);
}
};
handler.handle();
}
}
abstract class Handler<T> {
public T content;
public Handler(T content) {
this.content = content;
}
abstract void handle();
}
输出 (Output)
1
2
Test
Java 9 - Optional Class Improvements
Java 8中引入了可选类,以避免空检查和NullPointerException问题。 在Java 9中,添加了三种新方法来改进其功能。
- stream()
- ifPresentOrElse()
- or()
stream() method
语法 (Syntax)
public Stream<T> stream()
如果存在值,则返回仅包含该值的顺序Stream,否则返回空Stream。
例子 (Example)
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Tester {
public static void main(String[] args) {
List<Optional<String>> list = Arrays.asList (
Optional.empty(),
Optional.of("A"),
Optional.empty(),
Optional.of("B"));
//filter the list based to print non-empty values
//if optional is non-empty, get the value in stream, otherwise return empty
List<String> filteredList = list.stream()
.flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty())
.collect(Collectors.toList());
//Optional::stream method will return a stream of either one
//or zero element if data is present or not.
List<String> filteredListJava9 = list.stream()
.flatMap(Optional::stream)
.collect(Collectors.toList());
System.out.println(filteredList);
System.out.println(filteredListJava9);
}
}
输出 (Output)
[A, B]
[A, B]
ifPresentOrElse() method
语法 (Syntax)
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
如果存在值,则使用值执行给定操作,否则执行给定的基于空的操作。
例子 (Example)
import java.util.Optional;
public class Tester {
public static void main(String[] args) {
Optional<Integer> optional = Optional.of(1);
optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() ->
System.out.println("Not Present."));
optional = Optional.empty();
optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() ->
System.out.println("Not Present."));
}
}
输出 (Output)
Value: 1
Not Present.
or() method
语法 (Syntax)
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)
如果存在值,则返回描述该值的Optional,否则返回由供应函数生成的Optional。
例子 (Example)
import java.util.Optional;
import java.util.function.Supplier;
public class Tester {
public static void main(String[] args) {
Optional<String> optional1 = Optional.of("Mahesh");
Supplier<Optional<String>> supplierString = () -> Optional.of("Not Present");
optional1 = optional1.or( supplierString);
optional1.ifPresent( x -> System.out.println("Value: " + x));
optional1 = Optional.empty();
optional1 = optional1.or( supplierString);
optional1.ifPresent( x -> System.out.println("Value: " + x));
}
}
输出 (Output)
Value: Mahesh
Value: Not Present
Java 9 - Multiresolution Image API
使用Java 9,引入了一种新的多分辨率图像API,它支持具有不同分辨率变体的多个图像。 此API允许将具有不同分辨率的一组图像用作单个多分辨率图像。 以下是多分辨率图像的主要操作。
Image getResolutionVariant(double destImageWidth, double destImageHeight) - 获取特定图像,该图像是表示指定大小的逻辑图像的最佳变体。
List《Image》 getResolutionVariants() - 获取所有分辨率变体的可读列表。
例子 (Example)
import java.io.IOException;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
import java.awt.Image;
import java.awt.image.MultiResolutionImage;
import java.awt.image.BaseMultiResolutionImage;
import javax.imageio.ImageIO;
public class Tester {
public static void main(String[] args) throws IOException, MalformedURLException {
List<String> imgUrls = List.of("http://www.iowiki.com/java9/images/logo.png",
"http://www.iowiki.com/java9/images/mini_logo.png",
"http://www.iowiki.com/java9/images/large_logo.png");
List<Image> images = new ArrayList<Image>();
for (String url : imgUrls) {
images.add(ImageIO.read(new URL(url)));
}
// read all images into one multiresolution image
MultiResolutionImage multiResolutionImage =
new BaseMultiResolutionImage(images.toArray(new Image[0]));
// get all variants of images
List<Image> variants = multiResolutionImage.getResolutionVariants();
System.out.println("Total number of images: " + variants.size());
for (Image img : variants) {
System.out.println(img);
}
// get a resolution-specific image variant for each indicated size
Image variant1 = multiResolutionImage.getResolutionVariant(156, 45);
System.out.printf("\nImage for destination[%d,%d]: [%d,%d]",
156, 45, variant1.getWidth(null), variant1.getHeight(null));
Image variant2 = multiResolutionImage.getResolutionVariant(311, 89);
System.out.printf("\nImage for destination[%d,%d]: [%d,%d]", 311, 89,
variant2.getWidth(null), variant2.getHeight(null));
Image variant3 = multiResolutionImage.getResolutionVariant(622, 178);
System.out.printf("\nImage for destination[%d,%d]: [%d,%d]", 622, 178,
variant3.getWidth(null), variant3.getHeight(null));
Image variant4 = multiResolutionImage.getResolutionVariant(300, 300);
System.out.printf("\nImage for destination[%d,%d]: [%d,%d]", 300, 300,
variant4.getWidth(null), variant4.getHeight(null));
}
}
输出 (Output)
Total number of images: 3
BufferedImage@7ce6a65d: type = 6 ColorModel: #pixelBits = 32 numComponents = 4
color space =java.awt.color.ICC_ColorSpace@548ad73b transparency = 3
has alpha = true isAlphaPre = false ByteInterleavedRaster: width =311
height = 89 #numDataElements 4 dataOff[0] = 3
BufferedImage@4c762604: type = 6 ColorModel: #pixelBits = 32 numComponents = 4
color space =java.awt.color.ICC_ColorSpace@548ad73b transparency = 3
has alpha = true isAlphaPre = false ByteInterleavedRaster: width =156
height = 45 #numDataElements 4 dataOff[0] = 3
BufferedImage@2641e737: type = 6 ColorModel: #pixelBits = 32 numComponents = 4
color space =java.awt.color.ICC_ColorSpace@548ad73b transparency = 3
has alpha = true isAlphaPre = false ByteInterleavedRaster: width =622
height = 178 #numDataElements 4 dataOff[0] = 3
Image for destination[156,45]: [311,89]
Image for destination[311,89]: [311,89]
Image for destination[622,178]: [622,178]
Image for destination[300,300]: [622,178]
CompletableFuture API Improvements
在Java 8中引入了CompletableFuture类来表示Future,可以通过设置其值和状态明确来完成。 它可以用作java.util.concurrent.CompletionStage。 它支持在未来完成时触发的依赖功能和操作。 在java 9中,CompletableFuture API得到了进一步的增强。 以下是对API进行的相关更改。
- 支持延迟和超时。
- Improved support for subclassing.
- 新工厂方法增加了。
支持延迟和超时
public CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit)
如果在给定超时之前没有完成,则此方法使用给定值完成此CompletableFuture。
public CompletableFuture<T> orTimeout(long timeout, TimeUnit unit)
如果在给定的超时之前没有完成,则此方法异常地使用TimeoutException完成此CompletableFuture。
改进了对子类化的支持
public Executor defaultExecutor()
它返回用于未指定Executor的异步方法的默认Executor。 可以在子类中重写此方法以返回Executor以提供一个独立的线程作为最小值。
public <U> CompletableFuture<U> newIncompleteFuture()
返回CompletionStage方法返回的类型的新不完整CompletableFuture。 CompletableFuture类的子类应覆盖此方法,以返回与此CompletableFuture相同的类的实例。 默认实现返回CompletableFuture类的实例。
新工厂方法
public static <U> CompletableFuture<U> completedFuture(U value)
此工厂方法返回已使用给定值完成的新CompletableFuture。
public static <U> CompletionStage<U> completedStage(U value)
此工厂方法返回一个新的CompletionStage,它已使用给定值完成,并且仅支持接口CompletionStage中存在的那些方法。
public static <U> CompletionStage<U> failedStage(Throwable ex)
此工厂方法返回一个新的CompletionStage,它已使用给定的异常异常完成,并且仅支持接口CompletionStage中存在的那些方法。
Java 9 - Miscellaneous features
除了上面提到的功能,使用Java 9,JDK平台还有很多增强功能。 其中一些列在下面。
- GC(垃圾收集器)改进
- Stack-Walking API
- 过滤传入的序列化数据
- 弃用Applet API
- Indify String Concatenation
- Enhanced Method Handles
- Java平台日志记录API和服务
- 紧凑的字符串
- Nashorn的Parser API