目录

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文档页面,您将看到以下输出。

javadoc输出

支持搜索和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中的javadoc输出

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属性。

Boolean Class

Boolean类javadoc

用forRemoval弃用

以下是Java 9上的System类javadoc的示例,说明了对@Deprecated注释使用forRemoval属性。

System Class

系统类javadoc

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
↑回到顶部↑
WIKI教程 @2018