java9新特性

Java 9 新特性

Java 9 发布于 2017 年 9 月 22 日,带来了很多新特性,其中最主要的变化是已经实现的模块化系统。接下来我们会详细介绍 Java 9 的新特性。

Java 9 新特性

  • 模块系统:模块是一个包的容器,Java 9 最大的变化之一是引入了模块系统(Jigsaw 项目)。
  • REPL (JShell):交互式编程环境。
  • HTTP 2 客户端
    • HTTP/2标准是HTTP协议的最新版本,
    • 新的 HTTPClient API 支持 **WebSocket **和 HTTP2 流以及服务器推送特性。
  • 改进的 Javadoc:Javadoc 现在支持在 API 文档中的进行搜索。另外,Javadoc 的输出现在符合兼容 HTML5 标准。
  • 多版本兼容 JAR 包:多版本兼容 JAR 功能能让你创建仅在特定版本的 Java 环境中运行库程序时选择使用的 class 版本。
  • 集合工厂方法
    • List,Set 和 Map 接口中,新的静态工厂方法可以创建这些集合的不可变实例。
  • 私有接口方法
    • 在接口中使用private私有方法。我们可以使用 private 访问修饰符在接口中编写私有方法。
  • 进程 API: 改进的 API 来控制和管理操作系统进程。引进 java.lang.ProcessHandle 及其嵌套接口 Info 来让开发者逃离时常因为要获取一个本地进程的 PID 而不得不使用本地代码的窘境。
  • 改进的 Stream API
    • 改进的 Stream API 添加了一些便利的方法,使流处理更容易,并使用收集器编写复杂的查询。
  • 改进 try-with-resources
    • 如果你已经有一个资源是 final 或等效于 final 变量,您可以在 try-with-resources 语句中使用该变量,而无需在 try-with-resources 语句中声明一个新变量。
  • 改进的弃用注解 @Deprecated:注解 @Deprecated 可以标记 Java API 状态,可以表示被标记的 API 将会被移除,或者已经破坏。
  • 改进钻石操作符(Diamond Operator) :匿名类可以使用钻石操作符(Diamond Operator)。
  • 改进 Optional 类
    • java.util.Optional 添加了很多新的有用方法,
    • Optional 可以直接转为 stream。
  • 多分辨率图像 API:定义多分辨率图像API,开发者可以很容易的操作和展示不同分辨率的图像了。
  • 改进的 CompletableFuture API : CompletableFuture 类的异步机制可以在 ProcessHandle.onExit 方法退出时执行操作。
  • 轻量级的 JSON API
    • 内置了一个轻量级的JSON API
  • 响应式流(Reactive Streams) API:
    • Java 9中引入了新的响应式流 API 来支持 Java 9 中的响应式编程。

更多的新特性可以参阅官网:What’s New in JDK 9

JDK 9 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk9-doc-downloads-3850606.html

在关于 Java 9 文章的实例,我们均使用 jdk 1.9 环境,你可以使用以下命令查看当前 jdk 的版本:

接下来我们将详细为大家简介 Java 9 的新特性:

序号特性
1模块系统
2REPL (JShell)
3改进的 Javadoc
4多版本兼容 JAR 包
5集合工厂方法
6私有接口方法
7进程 API
8Stream API
9try-with-resources
10@Deprecated
11内部类的钻石操作符(Diamond Operator)
12Optional 类
13多分辨率图像 API
14CompletableFuture API

Java 9 模块系统

Java 9 新特性 Java 9 新特性

Java 9 最大的变化之一是引入了模块系统(Jigsaw 项目)。

模块就是代码和数据的封装体。

  • 模块的代码被组织成多个包,每个包中包含Java类和接口;
  • 模块的数据则包括资源文件和其他静态信息。

Java 9 模块的重要特征

  • 是在其工件(artifact)的根目录中包含了一个描述模块的 module-info.class 文 件。
  • 工件的格式可以是传统的 JAR 文件或是 Java 9 新增的 JMOD 文件。
  • 这个文件由根目录中的源代码文件 module-info.java 编译而来。该模块声明文件可以描述模块的不同特征。

在 module-info.java 文件中,我们可以用新的关键词module来声明一个模块,如下所示。下面给出了一个模块com.mycompany.mymodule的最基本的模块声明。

module com.runoob.mymodule {
}

创建模块

接下来我们创建一个 com.runoob.greetings 的模块。

第一步

创建文件夹 C:>JAVA\src,然后在该目录下再创建与模块名相同的文件夹 com.runoob.greetings。

第二步

在 C:>JAVA\src\com.runoob.greetings 目录下创建 module-info.java 文件,代码如下:

module com.runoob.greetings { }

module-info.java 用于创建模块。这一步我们创建了 com.runoob.greetings 模块。

第三步

在模块中添加源代码文件,在目录 C:>JAVA\src\com.runoob.greetings\com\runoob\greetings 中创建文件 Java9Tester.java,代码如下:

package com.runoob.greetings;

public class Java9Tester {
   public static void main(String[] args) {
      System.out.println("Hello World!");
   }
}

第四步

创建文件夹 C:>JAVA\mods,然后在该目录下创建 com.runoob.greetings 文件夹,编译模块到这个目录下:

C:/>JAVA> javac -d mods/com.runoob.greetings src/com.runoob.greetings/module-info.java src/com.runoob.greetings/com/runoob/greetings/Java9Tester.java

第五步

执行模块,查看输出结果:

C:/>JAVA> java --module-path mods -m com.runoob.greetings/com.runoob.greetings.Java9Tester

Hello World!

module-path 指定了模块所在的路径。

-m 指定主要模块。

  • 创建目录 src/com.runoob.greetings

    • 在此目录下创建文件 module-info.java
    • 在此目录下创建文件夹 \com\runoob\greetings
      • 在greetings目录下创建:Java9Tester
  • 创建目录 mods/com.runoob.greetings

  • javac -d 输出目录 module-info.java目录 Java9Tester.java目录

  • java --module-path mods -m com.runoob.greetings/com.runoob.greetings.Java9Tester
    
    • 最后运行 C:\JAVA\mods\ com.runoob.greetings \com\runoob\greetings\ Java9Tester.class

Java 9 REPL (JShell)

Java 9 新特性 Java 9 新特性

REPL(Read Eval Print Loop)意为交互式的编程环境。

JShell 是 Java 9 新增的一个交互式的编程环境工具。它允许你无需使用类或者方法包装来执行 Java 语句。它与 Python 的解释器类似,可以直接 输入表达式并查看其执行结果。

执行 JSHELL

$ jshell
|  Welcome to JShell -- Version 9-ea
|  For an introduction type: /help intro
jshell>

查看 JShell 命令

输入 /help 可以查看 JShell相关的命令:

C:\Users\you>jshell
|  欢迎使用 JShell -- 版本 14.0.2
|  要大致了解该版本, 请键入: /help intro

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
|       类似 readline 的输入编辑的说明
|  id
|       片段 ID 以及如何使用它们的说明
|  shortcuts
|       片段和命令输入提示, 信息访问以及
|       自动代码生成的按键说明
|  context
|       /env /reload 和 /reset 的评估上下文选项的说明
|  rerun
|       重新评估以前输入片段的方法的说明

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 命令

/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() ,将传入的整型参数乘于 2 后返回:

jshell> int doubled(int i){ return i*2;}
|  created method doubled(int)
jshell> doubled(6)
$3 ==> 12
jshell>

退出 JShell

输入 /exit 命令退出 jshell:

jshell> /exit
| Goodbye 

Java 9 改进 Javadoc

Java 9 新特性 Java 9 新特性

javadoc 工具可以生成 Java 文档, Java 9 的 javadoc 的输出现在符合兼容 HTML5 标准。

Java 9 之前的旧版本文档

考虑以下文件代码 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...

执行以上命令会再 C:/JAVA 命令下生成文档页面,如下图所示:

img

Java 9 生成的文档兼容 HTML5 标准

使用 jdk 9 javadoc 命令中的 -html5 参数可以让生成的文档支持 HTML5 标准:

C:\JAVA> javadoc -d C:/JAVA -html5 Tester.java
Loading source file Tester.java...
  • 去 C盘 ,就能直接找到这些文件。

执行以上命令会再 C:/JAVA 命令下生成文档页面,如下图所示:

img

Java 9 新特性 Java 9 新特性

Java 9 集合工厂方法

Java 9 新特性 Java 9 新特性

Java 9 List,Set 和 Map 接口中,新的静态工厂方法可以创建这些集合的不可变实例。

这些工厂方法可以以更简洁的方式来创建集合。

旧方法创建集合

实例

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);
   }
}

//unmodifiableMap 无法改变的
//如果运行了这个方法后,在改变值,就会抛异常。
Exception in thread "main" java.lang.UnsupportedOperationException

执行输出结果为:

[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)
  • List 和 Set 接口, of(…) 方法重载了 0 ~ 10 个参数的不同方法 。
  • Map 接口, of(…) 方法重载了 0 ~ 10 个参数的不同方法 。
  • Map 接口如果超过 10 个参数, 可以使用 ofEntries(…) 方法。

新方法创建集合

实例


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);
   }
}

//Exception in thread "main" java.lang.UnsupportedOperationException 如果改变集合的对象也会报错。


[A, B, C]
[A, B, C]
{A=Apple, B=Boy, C=Cat}
{A=Apple, B=Boy, C=Cat}

Java 9 私有接口方法

Java 9 新特性 Java 9 新特性

在 Java 8之前,接口可以有常量变量和抽象方法。

我们不能在接口中提供方法实现。如果我们要提供抽象方法和非抽象方法(方法与实现)的组合,那么我们就得使用抽象类。

实例

fatal 
英 /ˈfeɪtl//ˈfeɪtl/  全球(英国)  
简明 牛津 新牛津  韦氏  柯林斯 例句  百科
adj. 致命的;重大的;毁灭性的;命中注定的
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("");
    }
}
//编写接口 日志
interface Logging {
    /*String ORACLE = "Oracle_Database";
    String MYSQL = "MySql_Database";*/

    //定义了4个接口
    void logInfo(String message);
    void logWarn(String message);
    void logError(String message);
    void logFatal(String message);//致命的

    //获取连接
    void getConnection();
    //关闭连接
    void closeConnection();
}
//oracle 继承日志, 实现所有方法
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");
    }
}

以上实例执行输出结果为:

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 SE 8的接口中编写方法实现,仅仅需要使用 default 关键字来定义它们。

在 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 { 
}
//接口是 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 不仅像 Java 8 一样支持接口默认方法,同时还支持私有方法。

在 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");
   }
}

以上实例执行输出结果为:

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 新特性 Java 9 新特性

ava 9 改进的进程 API

Java 9 新特性 Java 9 新特性

在 Java 9 之前,Process API 仍然缺乏对使用本地进程的基本支持,例如获取进程的 PID 和所有者,进程的开始时间,进程使用了多少 CPU 时间,多少本地进程正在运行等。

Java 9 向 Process API 添加了一个名为 ProcessHandle 的接口来增强 java.lang.Process 类。

ProcessHandle 接口的实例标识一个本地进程,它允许查询进程状态并管理进程。

ProcessHandle 嵌套接口 Info 来让开发者逃离时常因为要获取一个本地进程的 PID 而不得不使用本地代码的窘境。

我们不能在接口中提供方法实现。如果我们要提供抽象方法和非抽象方法(方法与实现)的组合,那么我们就得使用抽象类。

ProcessHandle 接口中声明的 onExit() 方法可用于在某个进程终止时触发某些操作。

实例


public class Tester {
    public static void main(String[] args) throws IOException {
        //获取 notepad
        ProcessBuilder pb = new ProcessBuilder("notepad.exe");

        String np = "Not Present";
        //启动他
        Process p = pb.start();

        /*Process ID : 5096
        Command name : C:\Windows\System32\notepad.exe
        Command line : Not Present
        Start time: 2021-01-14T17:53:06.218
        Arguments : Not Present
        User : LAPTOP-01EONIAD\张三*/

        ProcessHandle.Info info = p.info();
        //pid
        System.out.printf("Process ID : %s%n", p.pid());
        //Command name : C:\Windows\System32\notepad.exe
        System.out.printf("Command name : %s%n", info.command().orElse(np));
        //Command line : Not Present
        System.out.printf("Command line : %s%n", info.commandLine().orElse(np));
        //Start time: 2021-01-14T17:53:06.218
        System.out.printf("Start time: %s%n",
                info.startInstant().map(i -> i.atZone(ZoneId.systemDefault())
                        .toLocalDateTime().toString()).orElse(np));
        //Arguments : Not Present
        System.out.printf("Arguments : %s%n",
                info.arguments().map(a -> Stream.of(a).collect(
                        Collectors.joining(" "))).orElse(np));
        //User : LAPTOP-01EONIAD\张三
        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

Java 9 新特性 Java 9 新特性

Java 9 改进的 Stream API

Java 9 新特性 Java 9 新特性

Java 9 改进的 Stream API 添加了一些便利的方法,使流处理更容易,

  • 并使用收集器编写复杂的查询。

Java 9 为 Stream 新增了几个方法:

  • dropWhile、
  • takeWhile、
  • ofNullable,
  • 为 iterate 方法新增了一个重载方法。

takeWhile 方法

语法

default Stream<T> takeWhile(Predicate<? super T> predicate)

takeWhile() 方法使用一个 断言 作为参数,

  • 返回给定 Stream 的子集直到断言语句第一次返回 false。
  • 如果第一个值不满足断言条件,将返回一个空的 Stream。

takeWhile() 方法在有序的 Stream 中,

  • takeWhile 返回从开头开始的尽量多的元素;
  • 在无序的 Stream 中,takeWhile 返回从开头开始的符合 Predicate 要求的元素的子集。

实例

Predicate 
英 /ˈprɛdɪˌkeɪt//ˈpredɪkət; ˈpredɪkeɪt/  全球(英国)  
简明 牛津 新牛津  韦氏  柯林斯 例句  百科
n. 谓语,述语
v. 使……基于;断言;暗示
adj. 谓语的,述语的
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 方法在碰到空字符串时停止循环输出,执行输出结果为:

abc

dropWhile 方法

语法

default Stream<T> dropWhile(Predicate<? super T> predicate)

dropWhile 方法和 takeWhile 作用相反的,使用一个断言作为参数,直到断言语句第一次返回 false 才返回给定 Stream 的子集。

实例

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);
   } 
}

以上实例 dropWhile 方法在碰到空字符串时开始循环输出,执行输出结果为:

ef

iterate 方法

语法

static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
  • 方法允许使用初始种子值创建顺序(可能是无限)流,
    • 并迭代应用指定的下一个方法。 当指定的 hasNext 的 predicate 返回 false 时,迭代停止。

实例

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);
   } 
}

ofNullable 方法

语法

static <T> Stream<T> ofNullable(T t)

ofNullable 方法可以预防 NullPointerExceptions 异常, 可以通过检查流来避免 null 值。

  • 如果指定元素为非 null,则获取一个元素并生成单个元素流,
  • 元素为 null 则返回一个空流。

实例

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 有一个不为null的 stream
0 有0个

Java 9 新特性 Java 9 新特性

Java 9 改进的 try-with-resources

Java 9 新特性 Java 9 新特性

try-with-resources 是 JDK 7 中一个新的异常处理机制,

  • 它能够很容易地关闭在 try-catch 语句块中使用的资源。
  • 所谓的资源(resource)是指在程序完成后,必须关闭的对象。
  • try-with-resources 语句确保了每个资源在语句结束时关闭。
  • 所有实现了 java.lang.AutoCloseable 接口(其中,它包括实现了 java.io.Closeable 的所有对象),可以使用作为资源。

try-with-resources 声明在 JDK 9 已得到改进。

  • 如果你已经有一个资源是 final 或等效于 final 变量,
  • 您可以在 try-with-resources 语句中使用该变量,
    • 而无需在 try-with-resources 语句中声明一个新变量。

实例

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,然后才能使用它。

在 Java 9 中,我们不需要声明资源 br1 就可以使用它,并得到相同的结果。

实例

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

在处理必须关闭的资源时,使用try-with-resources语句替代try-finally语句。 生成的代码更简洁,更清晰,并且生成的异常更有用。 try-with-resources语句在编写必须关闭资源的代码时会更容易,也不会出错,而使用try-finally语句实际上是不可能的。

Java 9 改进的 @Deprecated 注解

Java 9 新特性 Java 9 新特性

注解 @Deprecated 可以标记 Java API 状态,可以是以下几种:

  • 使用它存在风险,可能导致错误
  • 可能在未来版本中不兼容
  • 可能在未来版本中删除
  • 一个更好和更高效的方案已经取代它。

Java 9 中注解增加了两个新元素:sinceforRemoval

  • since: 元素指定已注解的API元素已被弃用的版本。
  • forRemoval: 元素表示注解的 API 元素在将来的版本中被删除,应该迁移 API。

以下实例为 Java 9 中关于 Boolean 类的说明文档,文档中 @Deprecated 注解使用了 since 属性:Boolean Class

img

以下实例为在 Java 9 中关于系统类的说明文档,文档中 @Deprecated 注解使用了 forRemoval 属性:System Class

img

Java 9 新特性 Java 9 新特性

Java 9 钻石操作符(Diamond Operator)

Java 9 新特性 Java 9 新特性

钻石操作符是在 java 7 中引入的,可以让代码更易读,但它不能用于匿名的内部类。

在 java 9 中, 它可以与匿名的内部类一起使用,从而提高代码的可读性。

考虑以下 Java 9 之前的代码:

实例

//定义一个抽象类,泛型是T
abstract class Handler<T> {
    //定义 T 类型的 content
    public T content;

    //对 content 赋值
    public Handler(T content) {
        this.content = content;
    }

    //定义抽象方法 handle
    abstract void handle();
}

public class Tester {
    public static void main(String[] args) {
        //创建一个 Integer 类型的 handle ,并重写其方法。
        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();
        
    }
}

执行输出结果为:

1
2
Test

在 Java 9 中,我们可以在匿名类中使用 <在9之前 这里有内容> 操作符,如下所示:

实例

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

Java 9 改进的 Optional 类

Java 9 新特性 Java 9 新特性

Optional 类在 Java 8 中引入,Optional 类的引入很好的解决空指针异常。。在 java 9 中, 添加了三个方法来改进它的功能:

  • stream()
  • if Present Or Else()
  • or()

stream() 方法

语法

public Stream<T> stream()
  • stream 方法的作用就是将 Optional 转为一个 Stream,
    • 如果该 Optional 中包含值,那么就返回包含这个值的 Stream,
    • 否则返回一个空的 Stream(Stream.empty())。

实例

public class TestMain {
    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]*/
    }
}

执行输出结果为:

[A, B]
[A, B]

ifPresentOrElse() 方法

语法

public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)

ifPresentOrElse 方法的改进就是有了 else,接受两个参数 Consumer 和 Runnable。

ifPresentOrElse 方法的用途是,

  • 如果一个 Optional 包含值,
    • 则对其包含的值调用函数 action,即 action.accept(value),
    • 这与 ifPresent 一致;与 ifPresent 方法的区别在于,
  • ifPresentOrElse 还有第二个参数 emptyAction
    • —— 如果 Optional 不包含值,
    • 那么 ifPresentOrElse 便会调用 emptyAction,即 emptyAction.run()。

实例

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)

如果值存在,返回 Optional 指定的值,否则返回一个预设的值。

实例

public class Tester {
   public static void main(String[] args) {
       
        //定义 Optional 赋值 Mahesh
        Optional<String> optional1 = Optional.of("Mahesh");
        //定义一个 没有赋值的 Supplier
        Supplier<Optional<String>> supplierString = () -> Optional.of("Not Present");

        //optional1 进行调用
        optional1 = optional1.or( supplierString);
        //进行打印。Value: Mahesh
        optional1.ifPresent( x -> System.out.println("Value: " + x));

        //重新赋值 为null
        optional1 = Optional.empty();

        //再次调用。 必须再次调用
        optional1 = optional1.or( supplierString);
        //执行。 结果为:Value: Not Present
        optional1.ifPresent( x -> System.out.println("Value: " + x));
   }  
}

执行输出结果为:

Value: Mahesh
Value: Not Present

Java 9 多分辨率图像 API

Java 9 新特性 Java 9 新特性

Java 9 定义多分辨率图像 API,开发者可以很容易的操作和展示不同分辨率的图像了。

以下是多分辨率图像的主要操作方法:

  • Image getResolutionVariant(double destImageWidth, double destImageHeight) − 获取特定分辨率的图像变体-表示一张已知分辨率单位为DPI的特定尺寸大小的逻辑图像,并且这张图像是最佳的变体。。
  • List 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.runoob.com/wp-content/themes/runoob/assets/img/runoob-logo@2x.png",
         "http://www.runoob.com/wp-content/themes/runoob/assets/img/runoob-logo.png",
         "http://www.runoob.com/wp-content/themes/runoob/assets/images/qrcode.png");
 
      List<Image> images = new ArrayList<Image>();
 
      for (String url : imgUrls) {
         images.add(ImageIO.read(new URL(url)));
      }
 
      // 读取所有图片
      MultiResolutionImage multiResolutionImage = 
         new BaseMultiResolutionImage(images.toArray(new Image[0]));
 
      // 获取图片的所有分辨率
      List<Image> variants = multiResolutionImage.getResolutionVariants();
 
      System.out.println("Total number of images: " + variants.size());
 
      for (Image img : variants) {
         System.out.println(img);
      }
 
      // 根据不同尺寸获取对应的图像分辨率
      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));
   }  
}

Java 9 改进的 CompletableFuture API

Java 9 新特性 Java 9 新特性

Java 8 引入了 CompletableFuture 类,

  • 可能是 java.util.concurrent.Future 明确的完成版(设置了它的值和状态),
  • 也可能被用作java.util.concurrent.CompleteStage 。支持 future 完成时触发一些依赖的函数和动作。Java 9 引入了一些CompletableFuture 的改进:

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 里的接口。

Java 9 新特性 Java 9 新特性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值