Java 9 新特性概览

作者: 一字马胡
转载标志 【2017-11-03】

更新日志

日期 更新内容 备注
2017-11-03 添加转载标志 持续更新

pre-reade&本文涉及的内容

首先,你可以在Java 9 Download下载java 9,然后就可以体验java 9了。本文是对java 9新特性的概览而不是详解,因为要详解的话需要收集大量的信息,而且有可能还不能覆盖所有特性,还有一点是本人才疏学浅,未免对新事物的理解过于迟钝,所以不太可能很快理解java 9中的新特性,比如java 9为什么要有某个特性,为什么增加这个特性,为什么删除了某个东西,这些都需要长期的技术积累和实践,从实际项目中来发现这些需求。本文涉及的java 9的新特性有一些会多讲一些篇幅,有一些会一带而过,比如本文比较在意的新增的API,会写一些示例代码来体验,而对于比较底层的JVM优化等内容不会涉及太多(无能为力,慢慢补上吧!)。下面先将本文的主要内容做一下索引。

  1. Java Modular System
  2. Enhance Process API
  3. Enhance Collection API
  4. Enhance Streams API
  5. Enhance Optional API
  6. Reactive API Support(RxJava)
  7. Private Methods of Interface
  8. Java Shell Support(REPL)
  9. Enhance Javadoc(search)
  10. Other Details

本文将基于上面提到的10点内容对java 9的新特性进行浅读解读,Java 8已经足够强大,但是java 9应该比java 8 要更强大,并且java的发版在未来会加快速度,需要快速学习啊。对于java 9 更为详细的描述应该参考更多的资料,最好可以结合jdk源码(或者openjdk源码)来看更好。

Java 9 新特性

Java Modular System

Java 9 一个比较大的改动就是增加了模块系统,基于 Jigsaw [ˈdʒɪgsɔ:] 项目,这是一个较为庞大复杂的项目,它的目标主要是下面两点:

  • 可靠的配置:明确模块边界和模块之间的依赖关系
  • 强封装性:通过封装模块内部私有细节,来避免不希望发生的依赖关系,也能避免一些安全问题等。

而Jigsaw被拆分为下面几个具体的项目:

  • JEP 261: Module System,实现模块化系统;
  • JEP 200: The Modular JDK,将JDK自身进行模块化;
  • JEP 201: Modular Source Code,按照模块化的形式,重构源代码,因为现有代码并不是划分到一个一个的模块里的。
  • JEP 220: Modular Run-Time Images,重新设计JDK和JRE的结构,定义新的URI scheme操作模块,类和资源(jrt)。
  • JEP 260: Encapsulate Most Internal APIs,按照模块化封装性的要求,将不希望暴露的内部API封装起来,如果确实证明是广泛需要的,就作为公共API公开出来。
  • JEP 282: jlink: The Java Linker。新的link工具

所谓JEP(JDK Enhancement Proposals),是java 9 中为了管理新特性而引入的代号。为了快速了解Jigsaw 项目在java 9 中的具体体现,下面先看一张图:

Java 9 新特性概览_第1张图片
java 9 模块依赖图

这是jdk现在的模块依赖关系图,可以发现所有的模块都是依赖一个模块叫做java.base,而java.base中包含了java语言层面的一些基础包,具体的java.base的详情可以参考Module java.base。介于该部分内容是java 9中的主要特性,但过于复杂,以至于都有专门的书籍来介绍这部分内容,所以更为细节的内容可以参考书籍Java 9 Modularity。下面来看一看如何在我们自己的项目中使用模块化编程呢。

比如,我们有三个模块,一个模块叫做com.hujian.base,提供一些基础信息内容,而第二个模块叫做com.hujian.extra,提供一些扩展信息,第三个模块叫做com.hujian.info,来提供较为全面的信息,他们之间的依赖关系为:com.hujian.extra依赖于com.hujian.base,而com.hujian.info依赖了com.hujian.base和com.hujian.extra。在java 9中,我们需要在每个模块中写一个module-info.java文件,里面描述模块的依赖关系,并且只有在模块暴露了出去,其他模块才能引用该模块。现在来看看上面三个模块的module-info.java应该怎么写:


对于com.hujian.base来说,它没有依赖其他模块,所以不需要依赖,但是,它需要提供服务,也就是
其他模块会引用该模块,所以他需要将自己的模块暴露出去,下面是它的module-info.java文件的内容:

 module com.hujian.base {

    exports com.hujian.base; //将模块暴露出去

}

而对于com.hujian.extra来说,它需要依赖com.hujian.base模块,并且com.hujian.info模块
会引用该模块,所以它的module-info.java是这样的:

 module com.hujian.extra {

    requires com.hujian.base;

    exports com.hujian.extra;

}

最后是com.hujian.info模块,它的module-info.java应该这样写:

 module com.hujian.info {

    requires com.hujian.base;
    require com.hujian.extra;

}

当然,这只是编写了module-info.java文件,实际的工作要比这个更多,但是我们可以借助IDE来实现这种模块编程,比如在
IDEA中,就可以很方便的实现。java 9中的模块系统也没有这么简单,介于还没有完全理解,该特性的描述就到此结束吧。

Enhance Process API

Process API提供了一种java程序和操作系统交互的能力,我们可以在代码中来获取关于进程的一些信息,java 9中新增了一个类ProcessHandle,使用这个类可以很方便的查询进程的一些信息。下面是该类的使用示例:


package com.hujian.java9;

import java.util.function.Consumer;

/**
 * Created by hujian06 on 2017/10/28.
 *
 * ProcessHandle demo
 */
public class ProcessHandleDemo {

    public static void main(String ... args) {

        long pid = ProcessHandle.current().pid();

        ProcessHandle.allProcesses()
                .forEach(new Consumer() {
                    @Override
                    public void accept(ProcessHandle processHandle) {
                        if (processHandle.pid() == pid) {
                            System.out.println("Current Process:" + pid + "\n" +
                                    processHandle.info());
                        }
                    }
                });
    }
}


上面的例子仅仅是获取了当前进程的进程id,更为有趣的应用可以参考ProcessHandle类的具体实现。

Enhance Collection API

在java 9中,分别为List、Set、Map增加了of静态工厂方法,来获取一个不可变的List、Set、Map。下面展示了java 9为List提供的of静态工厂方法集,Set和Map都是类似的就不赘述了:


static  List of()
static  List of(E e1)
static  List of(E e1, E e2)
static  List of(E e1, E e2, E e3)
static  List of(E e1, E e2, E e3, E e4)
static  List of(E e1, E e2, E e3, E e4, E e5)
static  List of(E e1, E e2, E e3, E e4, E e5, E e6)
static  List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7)
static  List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8)
static  List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9)
static  List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
static  List of(E... elements)

在java 9之前,如果我们想要获取一个不可变的List的话,可以使用下面的方法来实现:


        List emptyList = Collections.emptyList();

        List list = Collections.singletonList("java 9");

而在java 9中,只需要使用of就可以获取一个不可变的List,使用方法如下:


        List emptyStringList = List.of();
        List stringList = List.of("java 7", "java 8", "java 9");

Enhance Streams API

java 8中新增的Stream API可以让java开发者方便的使用计算机的并行能力来快速计算,关于java 8中的Stream的分析总结,可以参考文章Java Streams API,以及Java Stream的并行实现。Stream API的并行实现借助了Fork/Join并行框架,关于Fork/Join的介绍,可以参考文章Java Fork/Join并行框架。而在java 9中,Stream API新增了几个方法,下面展示了这些新增的方法:


default Stream dropWhile(Predicate predicate)
default Stream takeWhile(Predicate predicate)
static  Stream ofNullable(T t)
static  Stream iterate(T seed, Predicate hasNext, UnaryOperator next)

dropWhile方法和takeWhile方法是一对类似的方法,这两个方法适合用在有序流,而对于无序流来说,使用这两个方法会造成不可预料的结果。而ofNullable静态方法的作用非常有限,它将对元素T进行判断,如果是null,则返回一个空流,否则,返回一个只包含一个元素T的流。而新增的iterate方法类似于for循环,类似于下面的代码:


   for (T index=seed; hasNext.test(index); index = next.apply(index)) {
        //todo...
   }

下面是使用iterate这个新方法来生成一个流的示例代码:


        Stream.iterate( 0, n -> (n <= 100), n -> n + 1 )
                .forEach(System.out::println);

需要注意的是,只要test返回false,那么就会停止向前,这一点需要特别注意。下面来看一下dropWhile方法和takeWhile方法的使用示例以及他们的注意事项:


        Stream.of(1, 2, 3, 4)
                .takeWhile(new Predicate() {
                    @Override
                    public boolean test(Integer integer) {
                        return integer < 4;
                    }
                }).forEach(System.out::println);
                
        对于takeWhile来说,它会从第一个元素进行test,如果第一个元素test返回false,那么就会立刻返回整个流。
        否则,会一直test到第一个返回false的元素,然后截取前面这一段返回。
        
               Stream.of(1, 2, 3, 4)
                .dropWhile(new Predicate() {
                    @Override
                    public boolean test(Integer integer) {
                        return integer < 4;
                    }
                }).forEach(System.out::println);         

      dropWhile类似于是takeWhile的互补操作,对于同一个有序流,同一个test条件来说,他们两个方法返回的内容正好
      是整个流的内容,他们的区别在于,takeWhile是返回满足条件的流内容,而dropWhile将丢弃满足条件的流,返回的
      正是不满足条件的流。

Enhance Optional API

Optional类也是java 8新增的类,在java 9中对他有一些增强,新增了三个方法:


public void ifPresentOrElse(Consumer action, Runnable emptyAction)
public Optional or(Supplier> supplier)
public Stream stream()

首先是ifPresentOrElse方法,这个方法是对原来的方法ifPresent的增强,下面是ifPresentOrElse方法的具体实现:


    public void ifPresentOrElse(Consumer action, Runnable emptyAction) {
        if (value != null) {
            action.accept(value);
        } else {
            emptyAction.run();
        }
    }

可以看到,ifPresentOrElse方法在value为null的时候提供了例外的操作,这也是orElse的语义。接下来看新增的or方法,下面是整个方法的实现,以及对这个方法的描述:


/**
     * If a value is present, returns an {@code Optional} describing the value,
     * otherwise returns an {@code Optional} produced by the supplying function.
     *
     * @param supplier the supplying function that produces an {@code Optional}
     *        to be returned
     * @return returns an {@code Optional} describing the value of this
     *         {@code Optional}, if a value is present, otherwise an
     *         {@code Optional} produced by the supplying function.
     * @throws NullPointerException if the supplying function is {@code null} or
     *         produces a {@code null} result
     * @since 9
     */
    public Optional or(Supplier> supplier) {
        Objects.requireNonNull(supplier);
        if (isPresent()) {
            return this;
        } else {
            @SuppressWarnings("unchecked")
            Optional r = (Optional) supplier.get();
            return Objects.requireNonNull(r);
        }
    }

最为激动人心的应该是第三个方法stream,它提供了将Optional转换为Stream的实现,在java 9中,你已经可以将一个Optional直接转换为一个Stream了,下面是它的实现细节:


    public Stream stream() {
        if (!isPresent()) {
            return Stream.empty();
        } else {
            return Stream.of(value);
        }
    }

Reactive API Support(RxJava)

如果你接触过RxJava,那么就很好理解java 9中新增的Reactive内容了,下面首先展示了一个非常简单的使用示例:


package com.hujian.java9;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Flow.Subscriber;
import java.util.concurrent.Flow.Subscription;
import java.util.concurrent.SubmissionPublisher;

public class FlowDemo2 {
    private static final ExecutorService SERVICE = Executors.newFixedThreadPool(1);
    private static final int CAPATIAL = 1024;

    public static void main(String[] args) {
        // Create a publisher.
        SubmissionPublisher publisher = new SubmissionPublisher<>(SERVICE, CAPATIAL);

        // Create a subscriber and register it with the publisher.
        MySubscriber subscriber = new MySubscriber<>();
        publisher.subscribe(subscriber);

        // Publish several data items and then close the publisher.
        List.of("Java 7", "Java 8", "Java 9")
                .forEach(item -> publisher.submit(item));

        publisher.close();

        SERVICE.submit(() -> {
            //wait the publish job~
        });

        SERVICE.shutdownNow();

    }

    static class MySubscriber implements Subscriber {

        @Override
        public void onSubscribe(Subscription subscription) {
            subscription.request(3);
            System.out.println("");
        }

        @Override
        public void onNext(T item) {
            System.out.println(":" + item);
        }

        @Override
        public void onError(Throwable t) {
            t.printStackTrace();
        }

        @Override
        public void onComplete() {
            System.out.println("");
        }
    }
}

下面是涉及Reactive的几个新增的类,需要说明的一点是,这些内容出自java并发大师Doug Lea,所以性能问题不需要担心,例外一点是,因为这些Reactive的内容添加到了java 语言中,所以比起第三方类库(比如RxJava)来说更为安全和稳定,来看看涉及的几个类:


Flow
  Publisher
  Subscriber
  Subscription
  Processor
SubmissionPublisher

更为具体和深入的分析将在例外的文章中进行。本文点到为止,还有,毕竟出自并发大师之手,日后值得研究一番啊!

Private Methods of Interface

在java 8中,接口中可以有默认方法和静态方法的实现,但是还不支持private方法的实现,而在java 9中,我们可以在接口中实现private方法了,先看下面的示例:


package com.hujian.java9;

/**
 * Created by hujian06 on 2017/10/28.
 *
 * demo of interface
 *
 */
public class InterfeaceDemo {

    public static void main(String ... args) {

        A a = new A() {
            @Override
            public void af() {
                f();
            }
        };

        a.af();
    }

}

interface A {

    String finalString = "Tag";

    void af();

    default void f() {
        f1();
    }

    private void f1() {
        System.out.println(finalString + ":f1");
    }

}

f1是接口A中的默认实现。private方法和default和静态方法的区别在于,default方法和静态方法都是对外暴露的接口方法,而private方法是私有的,外部调用方是没有权限知道的。关于接口的不断更新,需要更为深入的讨论,再次先不做总结描述。

Java Shell Support(REPL)

现在,java语言也支持REPL了,就像下面展示的图片一样:

Java 9 新特性概览_第2张图片
JShell

Enhance Javadoc(search)

参考:Java® Platform, Standard Edition & Java Development Kit
Version 9 API Specification

以及java 8版本的javadoc:Java™ Platform, Standard Edition 8
API Specification

区别还是很明显的,java 9开始javadoc支持查找了,这一点是很明智的!下面看一下搜索效果图,这样是不是很快可以找到我们需要查找的类信息呢:

Java 9 新特性概览_第3张图片
java 9 javadoc

Other Details

  1. 对CompletableFuture类的增强,细节看代码吧!
  2. "_"不再可以是一个标志符,在java 9中已经升级为一个关键字了!
  3. HTTP/2 Client API(孵化,目前来看还是用不了啊,好像需要重新编译openjdk?),据说比Apache的HttpClients性能还要好啊,这一点很有吸引力啊,还是比较期待的
  4. 其他更改,可以参考
    • Java 9 - The Ultimate Feature List
    • Java 9 Features

本文简单分析了java 9的新特性,更为完整深入的java 9的特性应该搜集更多的资料来总结,关于是否要将目前的java版本升级到java 9,我的想法是,应该等等,一个原因是java 9和java 8比起来貌似没有太多性能优化方面的考虑(不包括我没有提到了jvm层面的优化,那些优化任何一个版本的java升级都会做大量的优化的),仅类库层面来说,java 9貌似没有太多的两点,新增的类好像不多,多数是对原有类的增强,但是貌似这些增强可有可无啊(个人觉得)。还有一个原因是,未来java的发版周期将更短,而java 9才刚发布不久,应该做一些深入的调研测试,等时机成熟再升级java 8到java 9也不迟~但是,如果目前还在使用java 8以前版本的javaer来说,我强烈建议升级到java 8,因为这个版本的java亮点很多,并且各方面表现都是很不错的,至于java 9,看各自的调研结论吧!

你可能感兴趣的:(Java 9 新特性概览)