Java 9新功能特性简介

16-07-10 banq
         

Java 9虽然从之前的2016-09-22推迟到2017-03-23,但是现在我们可以一窥其一些亮点新功能,亮点在:Jigsaw、工具、HTTP API和语言细节几个方面。

JIGSAW

将模块绑定成一个或多个包,提供比JAR更强的封装性。

允许向下扩展变成运行时的JAR,适合物联网IoT

缺点是没有模块版本。

module com.mysql.jdbc {
    // 依赖的模块
    requires java.sql;

    // 在模块中导出包
    exports com.mysql.jdbc;

    // Implements service with instance
    provides java.sql.Driver with com.mysql.jdbc.Driver;
}
<p>

改变了Javac和Java用法,以便使用模块:

javac -mp modulepath ...

java -mp modulepath -m modulename/moduleclass

jlink是可以用来连接一组模块,以及它们的传递依赖关系,创建一个自定义的模块化运行时缩影。

使用模块的ServiceLoader:

public abstract class BillingService {

  public static BillingService getInstance() {
     // Java SPI to find the instance
     ServiceLoader<BillingServiceProvider> sl =
         ServiceLoader.load(BillingServiceProvider.class);

     // Fetch first provider implementation
     Iterator<BillingServiceProvider> it = sl.iterator();

     return it.next().buildBillingService();
    }

    public abstract String takeMoney();
}
<p>

module anothermodule {
  exports de.exxcellent.anothermodule;
  requires de.exxcellent.java9;

  // Provide Service instance (SPI with Jigsaw modules)
  provides de.exxcellent.java9.jigsaw.spi.BillingServiceProvider
  with de.exxcellent.anothermodule.spi.MastercardBillingServiceProvider;
}
<p>

编译运行命令汇总:

$ mkdir -p target/module/de.exxcellent.java9
$ mkdir -p target/module/anothermodule

$ javac $(find playground/src/main/java -name "*.java") \
        -d target/module/de.exxcellent.java9
$ javac $(find playground-dependent/src/main/java -name "*.java")\
        -d target/module/anothermodule \
        -modulepath target/module

$ java  -modulepath target/module \
        -m anothermodule/de.exxcellent.anothermodule.TestJigsawSPI
Mastercard billed the money!
<p>

REPL:Jshell

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

jshell> 3 + 4 * 7
$1 ==> 31

jshell> int add(int a, int b) {
...>   return a+b;
...> }
|  created method add(int,int)

jshell> add(25, $1)
$3 ==> 56
<p>

HTML5 Javadoc

通过-html5参数激活;

搜索兼容

Html5 & 更新的Doclet API

提高的DocLint:

-Xdoclint/package:java.*,javax.*

进程控制

能够检查和检测以及杀死Process。

import java.io.IOException;
import static java.lang.System.out;

public class ControlProcess {

    /**
     * 启动一个进程process, 监听进程中断,检查进程细节,杀死进程
     */
    public static void main(String[] args) throws IOException, InterruptedException {
        Process sleeper = Runtime.getRuntime().exec("sleep 1h");

        // 获得 自己的或启动的进行的PIDs 
        out.println("Your pid is " + ProcessHandle.current().getPid());
        out.println("Started process is " + sleeper.getPid());

        ProcessHandle sleeperHandle = ProcessHandle.of(sleeper.getPid())   // Optional
                .orElseThrow(IllegalStateException::new);

        // 在退出进程做些善后
        sleeperHandle.onExit().thenRun(                                    // CompletableFuture
                () -> out.println("Sleeper exited")
        );

        // Get info on process
        out.printf("[%d] %s - %s\n",
                   sleeperHandle.getPid(),
                   sleeperHandle.info().user().orElse("unknown"),
                   sleeperHandle.info().commandLine().orElse("none"));

        // Kill a process
        sleeperHandle.destroy();

        // Give exit handler a chance to see the sleeper onExit()
        Thread.sleep(99);
    }
}

<p>

新的Collection

public class ImmutableCollections {

    /**
     * 快速创建一个不可变集合
     * <b>Note:</b> They do not accept {@code null} or duplicate entries (Set/Map)
     */
    public static void main(String args[]) {
        List<Integer> listOfNumbers = List.of(1, 2, 3, 4, 5/*, null*/);
        out.println(listOfNumbers);

        Set<Integer> setOfNumbers = Set.of(1, 2, 3, 4, 5/*, 1*/);
        out.println(setOfNumbers);

        Map<String, String> mapOfString = Map.of("key1", "value1", "key2", "value2");
        out.println(mapOfString);

        Map<String, String> moreMapOfString = Map.ofEntries(
                Map.entry("key1", "value1"),
                Map.entry("key2", "value2")/*,
                Map.entry("key1", "value3")*/
        );
        out.println(moreMapOfString);
    }
}
<p>

增强的Deprecated

@Deprecated(since ="1.5", forRemoval = true)
<p>

Stream

// All bytes from an InputStream at once
byte[] result = new ByteArrayInputStream(buf)
    .readAllBytes();

// 直接重定向InputStream 到 OutputStream
new ByteArrayInputStream(buf)
    .transferTo(System.out);
<p>

StackWalker

public class StackWalkerExample {

    /**
     * Easily traverse stackframes.
     */
    public static void main(String[] args) {
        walkAndFilterStackframe().forEach(out::println);
    }

    // return class/method only for our classes.
    private static List<String> walkAndFilterStackframe() {
        return StackWalker.getInstance().walk(s ->
                s.map( frame -> frame.getClassName()+"/"+frame.getMethodName() )
                        .filter(name -> name.startsWith("de.exxcellent"))
                        .limit(10)
                        .collect(Collectors.toList())
            );
    }

}
<p>

包名

this.getClass().getPackageName()
<p>

HTTP/2支持

/**
 * HTTP API 提供异步和同步功能,在异步模型
 * 任务会在线程threads (ExecutorService)执行
 */
public static void main(String[] args) throws Exception {
  HttpClient.getDefault()
    .request(URI.create("https://www.exxcellent.de"))
    .GET()
    .responseAsync() // CompletableFuture :D
    .thenAccept(httpResponse ->
        out.println(httpResponse.body(HttpResponse.asString()))
    );
  Thread.sleep(999); // Give worker thread some time.
}
<p>

性能

提高了竞争锁的性能

隔离代码缓存

更智能的Java编译

交叉编译

Javac -release n

等同于:

javac -source N -target N –bootclasspath rtN.jar ...

Java 9: A short summary & overview over the new fe

         

5