1 概述
JAVA 9(aka jdk 1.9)是JAVA编程语言开发的主要版本。 它的最初版本于2017年9月21日发布。Java9发布的主要目标是 -
为了使JDK和Java标准版平台模块化,可以将其划分为小型计算设备。
提高JDK和Java实现的整体安全性。
使Java代码库和大型应用程序的构建过程和维护变得轻松适用于JAVA SE和EE平台。
为Java平台设计和实现一个标准模块系统,可以很容易地应用于Platform和JDK。
新特性
和Java8相比,Java9中增加了90多项增强功能,其中最重要的增强功能如下所述 -
Moudle(模块) - 作为模块引入的一种新型Java编程组件,它是一种有名,自描述的代码和数据集合。
REPL(JShell) - 添加到Java平台的Read-Eval-Print Loop(REPL)功能。
HTTP 2客户端 - 支持Websockets和HTTP 2流和服务器推送功能的新HTTPClientAPI。
改进的JavaDocs- 支持HTML5输出生成。为生成的API文档提供搜索框。
Multirelease JAR - 增强了JAR格式,以便多个Java版本特定版本的类文件可以共存于一个归档中。
Collection Factory Methods(集合工厂方法) - 用于List,Set和Map接口的新静态工厂方法,以创建这些集合的不可变实例。
专用接口方法 -使用私有和私有静态方法的增强接口。
Process API Improvements(过程API改进) - 改进的API来控制和管理操作系统过程。
Stream API Improvements(流API改进) - 通过允许过滤对象序列化数据的传入流,从而增强安全性和健壮性。
Try With Resources Improvement(尝试使用资源改进) - 现在,final变量可以在try-with-resources语句中用作资源。
增强的@Deprecated注解 - 修改了@Deprecated注解,以提供有关API状态和预期处置的更多信息。
内部类钻石操作符 -允许钻石操作符与匿名类一起使用,如果可以表示推断类型的参数类型。
可选类改进 -将新的有用方法添加到java.util.Optional类中。
多分辨率图像API- 支持将具有不同分辨率的一组图像封装成单个多分辨率图像。
CompletableFuture API改进 - CompletableFuture类的异步机制可以在ProcessHandle.onExit方法退出时执行操作。
轻量级JSON- 一个轻量级API,用于在Java 9中通过json使用和生成文档和数据流。
Reactive Streams API - 已引入Java SE 9中新的Reactive Streams API以支持java 9中的响应式编程。
2环境变量设置
1、本地环境变量设置
如果您想为Java编程语言设置自己的环境,那么本节将指导您完成整个过程。 请按照以下步骤设置您的Java环境。
Java SE可以免费下载。 要下载请点击这里,请下载与您的操作系统兼容的版本。
按照说明下载Java,然后运行.exe以在您的机器上安装Java。 一旦你在你的机器上安装了Java,你就需要设置环境变量来指向正确的安装目录。
为Windows2000/XP设置环境变量
假设你已经在c:\ Program Files \ java \ jdk目录中安装了Java -
右键单击“我的电脑”并选择“属性”。
点击“高级”选项卡下的“环境变量”按钮。
现在,编辑'Path'变量并将路径添加到Java可执行文件目录的末尾。 例如,如果路径当前设置为C:\ Windows \ System32,则按以下方式进行编辑
C:\Windows\System32;c:\Program Files\java\jdk\bin |
为Windows95/98/ME设置环境变量
假设你已经在c:\ Program Files \ java \ jdk目录中安装了Java -
编辑'C:\ autoexec.bat'文件并在最后添加以下行 -
SET PATH = %PATH%;C:\Program Files\java\jdk\bin |
为Liunx,UNIX,Solaris,FreeBSD设置环境变量
应将环境变量PATH设置为指向已安装Java二进制文件的位置。 如果您在执行此操作时遇到问题,请参阅您的shell文档。
例如,如果您使用bash作为您的shell,那么您将在.bashrc的末尾添加以下行 -
export PATH = /path/to/java:$PATH' |
2、通用Java编辑器
要编写Java程序,您需要一个文本编辑器。 市场上还有更复杂的IDE。 下面简要介绍最流行的一些 -
Notepad - 在Windows机器上,您可以使用任何简单的文本编辑器,如记事本(建议用于本教程)或写字板。 Noteppad++也是一个免费的文本编辑器,增强了设施。
Netbeans - 这是一个开源和免费的Java IDE,可以从https://www.netbeans.org/index.html下载。
Eclipse - 它也是Eclipse开源社区开发的Java IDE,可以从https://www.eclipse.org/下载。
IDE或集成开发环境,提供所有常用的工具和设施以帮助进行编程,例如源代码编辑器,构建工具和调试器等。
3 模块系统(Module System)
Java 9是一种称为模块的新型编程组件。 一个模块是一个自我描述的代码和数据集合,并有一个名称来标识它。
特性
使用Modules组件,Java 9中增加了以下功能:
A、引入了一个新的可选阶段,即链接时间。 这个阶段介于编译时间和运行时间之间。 在此阶段,可以组合和优化一组模块,使用jlink工具制作自定义运行时映像。
B、javac,jlink和java有额外的选项来指定模块路径,它们进一步定位模块的定义。
C、JAR格式更新为模块化JAR,其中包含根目录中的module-info.class文件。
D、引入了JMOD格式,这是一种打包格式(类似于JAR),可以包含本机代码和配置文件。
创建Module
下面是创建一个名称为com.tutorialspoint.greetings的Module的步骤。
步骤1
创建一个文件夹C:\> JAVA \ src。 现在创建一个与我们创建的模块名称相同的文件夹com.tutorialspoint.greetings。
第2步
使用以下代码在C:\> JAVA \ src \com.tutorialspoint.greetings文件夹中创建module-info.java。
module-info.java
module com.tutorialspoint.greetings { } |
module-info.java是用来创建模块的文件。 在这一步中,我们创建了一个名为com.tutorialspoint.greetings的模块。 按照惯例,这个文件应该驻留在名称与模块名称相同的文件夹中。
第3步
在模块中添加源代码。 使用以下代码在C:\> JAVA \ src \ com.tutorialspoint.greetings \com \ tutorialspoint \ greetings文件夹中创建Java9Tester.java。
Java9Tester.java
package com.tutorialspoint.greetings;
public class Java9Tester { public static void main(String[] args) { System.out.println("Hello World!"); } } |
按照惯例,模块的源代码位于模块名称相同的目录中。
步骤4
创建一个文件夹C:\> JAVA \ mods。 现在创建一个与我们创建的模块名称相同的文件夹com.tutorialspoint.greetings。 现在编译模块到mods目录。
C:/ > JAVA > javac -d mods/com.tutorialspoint.greetings src/com.tutorialspoint.greetings/module-info.java src/com.tutorialspoint.greetings/com/tutorialspoint/greetings/Java9Tester.java |
第5步
让我们运行模块来查看结果。 运行以下命令。
C:/ > JAVA > java --module-path mods -m com.tutorialspoint.greetings/com.tutorialspoint.greetings.Java9Tester |
这里module-path将模块位置作为mods提供,而-m则表示主模块。
输出
你将会在控制台看到以下输出:
Hello World! |
4 REPL(JShell)
REPL代表Read-Eval-Print Loop。Java具有REPL功能。 使用REPL,我们可以编写和测试基于java的逻辑,而无需使用javac编译并直接查看计算结果。
运行JShell
打开控制台,然后输入jshell。
$ jshell | Welcome to JShell -- Version 9-ea | For an introduction type: /help intro jshell> |
查看JShell命令
进入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 |
使用JShell命令
进入jshell以后,输入/ imports命令开始运行并查看使用的导入。
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并返回其加倍的值。
jshell> int doubled(int i){ return i*2;} | created method doubled(int) jshell> doubled(6) $3 ==> 12 jshell> |
退出JShell
输入/exit。
jshell> /exit | Goodbye |
5 改进的JavaDocs
Java文档可以使用javadoc工具生成。 它目前以html4.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"); } } |
现在运行jdk7的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文档页面,您将看到以下输出。
新的java文档支持HTML5和搜索
使用-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文档页面,您将看到以下输出。
6 Multirelease JAR
在java9中,引入了一个新特性,其中jar格式得到了增强,可以根据平台维护和使用不同版本的java类或资源。 在JAR中,文件MANIFEST.MF文件的主要部分中有一个条目Multi-Release:true。 META-INF目录还包含版本子目录,其子目录(从9开始,用于Java 9)存储版本特定的类和资源文件。
在这个例子中,我们将使用多版本的jar来创建两个版本的Tester.java文件,一个用于jdk 7,另一个用于jdk 9,并在不同的jdk版本上运行。
第1步 - 创建一个文件夹c:/test / java7 / com / tutorialspoint。 用以下内容创建Test.java-
Tester.java
package com.tutorialspoint;
public class Tester { public static void main(String[] args) { System.out.println("Inside java 7"); } } |
第2步 - 创建一个文件夹c:/test / java9 / com / tutorialspoint。 用以下内容创建Test.java-
Tester.java
package com.tutorialspoint;
public class Tester { public static void main(String[] args) { System.out.println("Inside java 9"); } } |
编译源代码
C:\test > javac --release 9 java9/com/tutorialspoint/Tester.java
C:\JAVA > javac --release 7 java7/com/tutorialspoint/Tester.java |
创建multi-releasejar
C:\JAVA > jar -c -f test.jar -C java7 . --release 9 -C java9. Warning: entry META-INF/versions/9/com/tutorialspoint/Tester.java, multiple resources with same name |
使用JDK7运行
C:\JAVA > java -cp test.jar com.tutorialspoint.Tester Inside Java 7 |
使用JDK9运行
C:\JAVA > java -cp test.jar com.tutorialspoint.Tester Inside Java 9 |
7 集合工厂方法
在Java9中,新的工厂方法被添加到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); } } |
输出
[A, B, C] [A, B, C] {A=Apple, B=Boy, C=Cat} |
新方法
使用java9,以下方法将被添加到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) |
几点注意的地方:
对于List和Set接口,of(...)方法重载为0到10个参数,和一个可变参数。
对于Map接口,of(...)方法重载为有0到10个参数。
如果Map接口的参数超过10个,则可以使用ofEntries(...)方法接受可变参数。
创建集合的新方式
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); } } |
输出
[A, B, C] [A, B, C] {A=Apple, B=Boy, C=Cat} {A=Apple, B=Boy, C=Cat} |
8 私有接口方法
在java8之前,接口可以有以下类型的变量/方法。
常量变量
抽象方法
所以我们不能在接口中实现方法,或者更确切地说,在Java8之前实现默认方法。请参阅示例。
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(); } |
输出
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接口可以有以下类型的变量/方法。
常量变量
抽象方法
默认方法
静态方法
让我们使用Java8在接口中使用默认实现和静态方法。
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"); } } |
输出
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接口可以有以下类型的变量/方法。
常量变量
抽象方法
默认方法
静态方法
私有方法
私有静态方法
让我们拥有私有方法并在Java9中使用它们。
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"); } } |
输出
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 |
9 Process API改进
在负责控制和管理操作系统进程的Java9 Process API中已经有了相当大的改进。ProcessHandle Class现在提供进程的本机进程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)); } } |
输出
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 |
10 Stream API改进
流是在Java中引入的,以帮助开发人员从一系列对象中执行聚合操作。 使用Java 9,添加几个可以使流更好使用的方法。
takeWhile(PredicateInterface)
语法
default Stream<T> takeWhile(Predicate<? super T> predicate) |
takeWhile方法获取所有值直到断言接口返回false。 在有序流的情况下,它返回一个流,该流包含从此流中匹配给定断言接口的元素的最长前缀。
示例
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); } } |
输出
takeWhile方法获取所有a,b和c值,然后一旦字符串为空,它将停止执行。
abc |
dropWhile(Predicate Interface)
语法
default Stream<T> dropWhile(Predicate<? super T> predicate) |
dropWhile方法在开始时丢弃所有值,直到断言接口返回true。 在排序流的情况下,它返回包含该流剩余元素的流后,删除与给定断言接口匹配的元素的最长前缀。
示例
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); } } |
输出
dropWhile方法删除a,b和c值,然后一旦字符串为空,它将获取所有值。
ef ef |
iterate
语法
static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next) |
iterate方法现在具有hasNext断言作为参数,一旦hasNext谓词返回false,它将停止循环。
示例
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); } } |
输出
3 6 9 |
ofNullable
语法
static <T> Stream<T> ofNullable(T t) |
ofNullable方法被引入来防止NullPointerExceptions并避免对流进行空检查。 此方法返回包含单个元素的顺序流,如果非空,则返回空流。
示例
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); } } |
输出
1 0 |
11 Try With Resources改进
try-with-resources语句是一个包含正确声明的一个或多个资源的try语句。 这里资源是一个对象,一旦不再需要它就应该关闭。 try-with-resources语句确保在需求完成后关闭每个资源。 任何实现java.lang.AutoCloseable或java.io.Closeable接口的对象都可以用作资源。
在Java9之前,资源将在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(); } } } |
输出
test |
这里我们需要在try语句中声明资源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(); } } } |
输出
test |
12 增强的@Deprecated注解
在java5版本中引入了@deprecated注解。 用@Deprecated注解的程序元素意味着它不应该用于以下任何原因 -
它的使用可能会导致错误。
它可能在未来版本中不兼容。
它可能在未来的版本中被删除。
一个更好和更高效的替代方案已经取代它。
每当使用不推荐使用的元素时,编译器会生成警告。 使用Java 9,对@Deprecated注解进行了两项新的增强。
forRemoval - 指示注解的元素是否在将来的版本中被删除。 默认值是false。
since - 返回注释元素已过时的版本。 默认值是空字符串。
Deprecated的since
以下Java9上的布尔类javadoc示例说明了在@Deprecated注释中使用了since属性。
Boolean @Deprecated(since="9") public Boolean(boolean value) Deprecated. It is rarely appropriate to use this constructor. The static factoryvalueOf(boolean) is generally a better choice, as it is likely to yield significantly better space and time performance. Also consider using the final fields TRUE and FALSE if possible. Allocates a Boolean object representing the value argument. Parameters: value - the value of the Boolean. |
Deprecated的forRemoval
Java 9上的System类javadoc的以下示例说明了在@Deprecated注释中使用forRemoval属性。
runFinalizersOnExit @Deprecated(since="1.2", forRemoval=true) public static void runFinalizersOnExit(boolean value) Deprecated, for removal: This API element is subject to removal in a future version. This method is inherently unsafe. It may result in finalizers being called on live objects while other threads are concurrently manipulating those objects, resulting in erratic behavior or deadlock. This method is subject to removal in a future version of Java SE. Enable or disable finalization on exit; doing so specifies that the finalizers of all objects that have finalizers that have not yet been automatically invoked are to be run before the Java runtime exits. By default, finalization on exit is disabled. If there is a security manager, its checkExit method is first called with 0 as its argument to ensure the exit is allowed. This could result in a SecurityException. Parameters: value - indicating enabling or disabling of finalization Throws: SecurityException - if a security manager exists and its checkExit method doesn't allow the exit. |
13 内部类的钻石操作
在java7中引入了钻石操作符以使代码更具可读性,但它不能与匿名内部类一起使用。 在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(); } |
输出
1 2 Test |
对于Java9,我们可以使用具有匿名类的<>运算符,如下所示。
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(); } |
输出
1 2 Test |
14 可选类改进
在Java8中引入了可选类,以避免空检查和NullPointerException问题。 在Java 9中,添加了三种新方法来改进其功能。
stream()
ifPresentOrElse()
or()
stream()方法
语法
public Stream<T> stream() |
如果存在值,则返回仅包含该值的顺序流,否则返回空流。
示例
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); } } |
输出
[A, B] [A, B] |
ifPresentOrElse()方法
语法
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) |
如果存在值,则使用该值执行给定操作,否则执行给定的基于空的操作。
示例
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.")); } } |
输出
Value: 1 Not Present. |
or()方法
语法
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) |
如果存在值,则返回一个描述该值的可选项,否则返回由提供函数生成的可选项。
示例
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)); } } |
输出
Value: Mahesh Value: Not Present |
15多分辨率图像API
使用Java9,已经推出了一种新的多分辨率图像API,支持具有不同分辨率变体的多个图像。 该API允许将具有不同分辨率的一组图像用作单个多分辨率图像。 以下是多分辨率图像的主要操作。
Image getResolutionVariant(double destImageWidth, doubledestImageHeight)- 获取特定图像,这是最佳变体,以指定的大小表示此逻辑图像。
List <Image> getResolutionVariants() - 获取所有分辨率变体的可读列表。
示例
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.tutorialspoint.com/java9/images/logo.png", "http://www.tutorialspoint.com/java9/images/mini_logo.png", "http://www.tutorialspoint.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)); } } |
输出
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] |
16 CompletableFutureAPI改进
CompletableFuture类是在Java 8中引入的,可以通过设置其值和状态显式来完成。 它可以用作java.util.concurrent.CompletionStage。 它支持未来完成时触发的相关函数和操作。 在Java 9中,CompletableFuture API进一步得到了增强。 以下是对API进行的相关更改。
支持延迟和超时。
改进了对子类的支持。
添加了新的工厂方法。
支持延迟和超时
public CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit) |
如果在给定超时之前未完成,则此方法使用给定值完成此CompletableFuture。
public CompletableFuture<T> orTimeout(long timeout, TimeUnit unit) |
如果在给定的超时之前没有完成,则此方法异常地完成此CompletableFuture并带有TimeoutException。
改进了对子类的支持
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接口中存在的那些方法。
17 杂项功能
除了上面提到的功能,在Java9中,JDK平台还有更多的增强功能。 其中一些列在下面。
GC(垃圾收集器)改进
Stack-WalkingAPI
过滤序列化数据
弃用Applet API
指示字符串串联
增强方法句柄
Java平台日志API和服务
紧凑的字符串
Nashorn的解析器API