Java9新特性
Java9 新特性
REPL (JShell)
REPL(Read Eval Print Loop)意为交互式的编程环境。
JShell 是 Java 9 新增的一个交互式的编程环境工具。它允许你无需使用类或者方法包装来执行 Java 语句。它与 Python 的解释器类似,可以直接 输入表达式并查看其执行结果。
执行JShell
C:\Users\zdk>jshell
| 欢迎使用 JShell -- 版本 11.0.11
| 要大致了解该版本, 请键入: /help intro
jshell>
查看JShell命令
jshell> /help
| 键入 Java 语言表达式, 语句或声明。
| 或者键入以下命令之一:
| /list [<名称或 id>|-all|-start]
| 列出您键入的源
| /edit <名称或 id>
| 编辑源条目
| /drop <名称或 id>
| 删除源条目
| /save [-all|-history|-start] <文件>
| 将片段源保存到文件
| /open <file>
| 打开文件作为源输入
| /vars [<名称或 id>|-all|-start]
| 列出已声明变量及其值
| /methods [<名称或 id>|-all|-start]
| 列出已声明方法及其签名
| /types [<名称或 id>|-all|-start]
| 列出类型声明
| /imports
| 列出导入的项
| /exit [<integer-expression-snippet>]
| 退出 jshell 工具
| /env [-class-path <路径>] [-module-path <路径>] [-add-modules <模块>] ...
| 查看或更改评估上下文
| /reset [-class-path <路径>] [-module-path <路径>] [-add-modules <模块>]...
| 重置 jshell 工具
| /reload [-restore] [-quiet] [-class-path <路径>] [-module-path <路径>]...
| 重置和重放相关历史记录 -- 当前历史记录或上一个历史记录 (-restore)
| /history [-all]
| 您键入的内容的历史记录
| /help [<command>|<subject>]
| 获取有关使用 jshell 工具的信息
| /set editor|start|feedback|mode|prompt|truncation|format ...
| 设置配置信息
| /? [<command>|<subject>]
| 获取有关使用 jshell 工具的信息
| /!
| 重新运行上一个片段 -- 请参阅 /help rerun
| /<id>
| 按 ID 或 ID 范围重新运行片段 -- 参见 /help rerun
| /-<n>
| 重新运行以前的第 n 个片段 -- 请参阅 /help rerun
|
| 有关详细信息, 请键入 '/help', 后跟
| 命令或主题的名称。
| 例如 '/help /list' 或 '/help intro'。主题:
|
| intro
| jshell 工具的简介
| keys
| a description of readline-like input editing
| id
| 片段 ID 以及如何使用它们的说明
| shortcuts
| 片段和命令输入提示, 信息访问以及
| 自动代码生成的按键说明
| context
| /env /reload 和 /reset 的评估上下文选项的说明
| rerun
| 重新评估以前输入片段的方法的说明
jshell>
JShell 执行计算
以下实例执行 JShell 简单计算:
jshell> 3+5
$1 ==> 8
jshell> 9%4
$2 ==> 1
jshell> $1
$1 ==> 8
JShell使用和创建函数
jshell> int doubled(int i){return i*5;}
| 已创建 方法 doubled(int)
jshell> doubled(5)
$5 ==> 25
集合工厂方法
Java 9 List,Set 和 Map 接口中,新的静态工厂方法可以创建这些集合的不可变实例。
新方法创建集合
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)
简单使用示例
/**
* Java 9 List,Set 和 Map 接口中,新的静态工厂方法可以创建这些集合的不可变实例。
* 之前的方式:set = Collections.unmodifiableSet(set);
*/
public static void collectionFactoryTest() {
var set = Set.of("set1", "set2");
System.out.println(set);
// set为不可变集合,这里新增元素会抛出异常:java.lang.UnsupportedOperationException
// set.add("e");
Map<String, String> map = Map.of("A","Apple","B","Boy","C","Cat");
System.out.println(map);
// 之前的不可变类实现方式
// Collections.unmodifiableList(new ArrayList())
}
私有接口方法
在 Java 9 中,一个接口中能定义如下几种变量/方法:
- 常量
- 抽象方法
- 默认方法
- 静态方法
- 私有方法(新)
- 私有静态方法(新)
示例:
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");
}
}
Java9 改进的进程API
在 Java 9 之前,Process API 仍然缺乏对使用本地进程的基本支持,例如获取进程的 PID 和所有者,进程的开始时间,进程使用了多少 CPU 时间,多少本地进程正在运行等。
Java 9 向 Process API 添加了一个名为 ProcessHandle 的接口来增强 java.lang.Process 类。
ProcessHandle 接口的实例标识一个本地进程,它允许查询进程状态并管理进程。
ProcessHandle 嵌套接口 Info 来让开发者逃离时常因为要获取一个本地进程的 PID 而不得不使用本地代码的窘境。
我们不能在接口中提供方法实现。如果我们要提供抽象方法和非抽象方法(方法与实现)的组合,那么我们就得使用抽象类。
ProcessHandle 接口中声明的 onExit() 方法可用于在某个进程终止时触发某些操作。
示例:
/**
* Java9 改进的进程API
* @throws IOException io异常
*/
public static void processAPI() 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));
var infoInstant = info.startInstant().map(i -> i.atZone(ZoneId.systemDefault()).toLocalDateTime().toString()).orElse(np);
System.out.printf("Start time: %s%n", infoInstant);
var infoArguments = info.arguments().map(i -> Stream.of(i).collect(Collectors.joining(" "))).orElse(np);
System.out.printf("Arguments : %s%n", infoArguments);
System.out.printf("User : %s%n", info.user().orElse(np));
}
执行结果:
Process ID : 27372
Command name : C:\Windows\System32\notepad.exe
Command line : Not Present
Start time: 2021-07-25T10:47:55.322
Arguments : Not Present
User : 朱登奎-LEGION\zdk
Java9 改进的Stream API
Java 9 改进的 Stream API 添加了一些便利的方法,使流处理更容易,并使用收集器编写复杂的查询。
Java 9 为 Stream 新增了几个方法:dropWhile、takeWhile、ofNullable,为 iterate 方法新增了一个重载方法。
takeWhile
使用一个断言作为参数,返回给定 Stream 的子集直到断言语句第一次返回 false。如果第一个值不满足断言条件,将返回一个空的 Stream。
takeWhile() 方法在有序的 Stream 中,takeWhile 返回从开头开始的尽量多的元素;在无序的 Stream 中,takeWhile 返回从开头开始的符合 Predicate 要求的元素的子集。
定义:
default Stream<T> takeWhile(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
// Reuses the unordered spliterator, which, when encounter is present,
// is safe to use as long as it configured not to split
return StreamSupport.stream(
new WhileOps.UnorderedWhileSpliterator.OfRef.Taking<>(spliterator(), true, predicate),
isParallel()).onClose(this::close);
}
dropWhile
dropWhile 方法和 takeWhile 作用相反的,使用一个断言作为参数,直到断言语句第一次返回 false 才返回给定 Stream 的子集。
iterator
方法允许使用初始种子值创建顺序(可能是无限)流,并迭代应用指定的下一个方法。 当指定的 hasNext 的 predicate 返回 false 时,迭代停止。
ofNullable
ofNullable 方法可以预防 NullPointerExceptions 异常, 可以通过检查流来避免 null 值。
如果指定元素为非 null,则获取一个元素并生成单个元素流,元素为 null 则返回一个空流。
示例:
/**
* 输出:
* takeWhile:abc
* dropWhile:efhi
* iterator:369
* ofNullable:0
*/
public static void streamAPI() {
System.out.print("takeWhile:");
Stream.of("a","b","c","","e","f").takeWhile(s->!s.isEmpty()).forEach(System.out::print);
System.out.print("\ndropWhile:");
Stream.of("a","b","c","","e","f","","h","i").dropWhile(s->!s.isEmpty()).forEach(System.out::print);
System.out.print("\niterator:");
IntStream.iterate(3, x -> x < 10, x -> x + 3).forEach(System.out::print);
System.out.print("\nofNullable:");
System.out.println(Stream.ofNullable(null).count());
}
Java9 改进的Optional类
Optional 类在 Java 8 中引入,Optional 类的引入很好的解决空指针异常。。在 java 9 中, 添加了三个方法来改进它的功能:
- stream()
- ifPresentOrElse()
- or()
stream
stream 方法的作用就是将 Optional 转为一个 Stream,如果该 Optional 中包含值,那么就返回包含这个值的 Stream,否则返回一个空的 Stream(Stream.empty())。
ifPresentOrElse
ifPresentOrElse 方法的改进就是有了 else,接受两个参数 Consumer 和 Runnable。
ifPresentOrElse 方法的用途是,如果一个 Optional 包含值,则对其包含的值调用函数 action,即 action.accept(value),这与 ifPresent 一致;与 ifPresent 方法的区别在于,ifPresentOrElse 还有第二个参数 emptyAction —— 如果 Optional 不包含值,那么 ifPresentOrElse 便会调用 emptyAction,即 emptyAction.run()。
or
如果值存在,返回 Optional 指定的值,否则返回一个预设的值。
示例:
/**
* 输出:
* [A, B]
* Not Present.
* Present Value:A
* Not Present.
* Present Value:B
* Optional[Not Present.]
* Optional[A]
* Optional[Not Present.]
* Optional[B]
*/
public static void optionalAPI() {
List<Optional<String>> optionalList = Arrays.asList (Optional.empty(), Optional.of("A"), Optional.empty(), Optional.of("B"));
// stream
List<String> stringList = optionalList.stream().flatMap(Optional::stream).collect(Collectors.toList());
System.out.println(stringList);
// ifPresentOrElse
optionalList.forEach(optional -> optional.ifPresentOrElse(o -> System.out.println("Present Value:" + o),
() -> System.out.println("Not Present.")));
// or
optionalList.forEach(optional -> System.out.println(optional.or(() -> Optional.of("Not Present."))));
}
Java9 改进的 CompletableFuture API
Java 9 对 CompletableFuture 做的改进:
- 支持 delays 和 timeouts
- 提升了对子类化的支持
- 新的工厂方法
支持 delays 和 timeouts
public CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit)
在 timeout(单位在 java.util.concurrent.Timeunits units 中,比如 MILLISECONDS )前以给定的 value 完成这个 CompletableFutrue。返回这个 CompletableFutrue。
public CompletableFuture<T> orTimeout(long timeout, TimeUnit unit)
如果没有在给定的 timeout 内完成,就以 java.util.concurrent.TimeoutException 完成这个 CompletableFutrue,并返回这个 CompletableFutrue。
增强了对子类化的支持
做了许多改进使得 CompletableFuture 可以被更简单的继承。比如,你也许想重写新的 public Executor defaultExecutor() 方法来代替默认的 executor。
另一个新的使子类化更容易的方法是:
public <U> CompletableFuture<U> newIncompleteFuture()
新的工厂方法
Java 8引入了 CompletableFuture completedFuture(U value) 工厂方法来返回一个已经以给定 value 完成了的 CompletableFuture。Java 9以 一个新的 CompletableFuture failedFuture(Throwable ex) 来补充了这个方法,可以返回一个以给定异常完成的 CompletableFuture。
除此以外,Java 9 引入了下面这对 stage-oriented 工厂方法,返回完成的或异常完成的 completion stages:
- CompletionStage completedStage(U value): 返回一个新的以指定 value 完成的CompletionStage ,并且只支持 CompletionStage 里的接口。
- CompletionStage failedStage(Throwable ex): 返回一个新的以指定异常完成的CompletionStage ,并且只支持 CompletionStage 里的接口。
Others
平台级模块系统
进程API的改进
之前启动一个进程的唯一方法是:Runtime.getRuntime().exec();Java9新增ProcessHandle接口来增强java.lang.Process类。
try-with-resources的改进
jdk1.7开始引入了try-with-resources使得代码变得简洁,增强代码可读性,也能更好地管理资源避免内存泄漏。
但jdk1.7中try语句中不能直接使用外部声明的任何资源,需要重新声明一个额外的引用,Java9对这里进行了改进,可以直接引用外部声明的资源。

浙公网安备 33010602011771号