Java 8-11各版本中语言层面上的主要改动

目录

1 Java 8(LTS)

1.1 Lambda表达式和Stream API

1.2 方法引用

1.3 接口中的默认方法和静态方法

1.4 新的Date/Time API

1.5 Optional

1.6 JUC包下的变动

1.7 HashMap和ConcurrentHashMap的变动

2 Java 9

2.1 接口中的私有方法

2.2 改进try-with-resources

2.3 改进钻石操作符

2.4 Collections API

2.5 Stream API

2.6 不能使用单独下划线作为变量名

3 Java 10

3.1 var关键字

3.2 Optional API

3.3 Collections API

3.4 ByteArrayOutputStream API

3.5 PrintStream、PrintWriter、Scanner API

3.6 Reader API

4 Java 11(LTS)

4.1 增强var关键字

4.2 Collections API

4.3 String API

4.4 删除Thread.destroy()和Thread.stop(Throwable)方法


从Java 9发布后,Java改为了每6个月一发布的策略(之前都是好几年才发布一个大版本),以此来避免将众多新功能特性被集中捆绑到一个版本上,从而引发交付风险和跳票问题的发生,但是这也会给使用Java的程序员和上层框架开发者带来很大的学习成本和兼容适配上的压力。所以本系列的文章旨在介绍各个新版本中语言层面上的主要改动,因为这些改动才是对使用者来说最为关心的。而对于其他层面上的改动(例如JVM和安全等方面),本系列文章就不做介绍了(同时对于我自身而言,将来如果要升级Java版本的话,我就不至于再去官网乃至全网去查询这些新特性了)。

从Java的发布规划中,每三年会发布一个LTS版本(长期支持版本),而其它版本将会作为过渡版本。LTS版本能够获得三年的支持和更新,而过渡版本却只有6个月的生命周期。Java 8和Java11会是LTS版本,而Java 9和Java 10则是过渡版本。过渡版本虽然并不会使用它,但是也还是需要了解的,因为它们的新特性会累加到LTS版本中。而对于Java 8来说,可能许多人还不知道Lambda表达式和Stream API的存在,所以也还是有必要对Java 8中的一些主要的改动进行说明的。

另外还有一点需要说明:并不是说从Java 11开始(对于Java 8来说从8u201和8u202之后的版本也包括),Java就变成收费的了。对于个人使用的话,是不会进行收费的,收费仅是对于商业用户来说的。Oracle公司除了拥有OracleJDK之外,还有免费可以商业使用的OpenJDK(还有其他公司开发的一些可以免费使用的JDK)。这两个JDK共享绝大部分源码,在功能上几乎是一样的(在Java 12中变动比较大,OracleJDK 12中不包含OpenJDK 12中新添加的Shenandoah垃圾收集器,因为这是由RedHat主导开发的),核心差异是OpenJDK可以免费在开发、测试和生产环境中使用,但是只有半年时间的更新支持;而OracleJDK个人依然可以免费使用,但若在生产环境中商用就必须付费,可以有三年时间的更新支持。所以说,Oracle公司此举并不是为了让Java变成收费的编程语言,而是如果用户使用的是OpenJDK的话,迫使用户去不断升级JDK的版本,以此来推动Java的发展;当然如果你不想这么折腾的话,可以使用OracleJDK,但是需要购买商业许可证,从而只使用某一个特定大版本并持续获得小版本更新。

另外如果你并不在乎JDK中是否有严重bug需要修复,或者性能是否有增强,而且是在商业环境下使用OracleJDK的话,可以使用Java 8u201和8u202及以前的老版本,或者直接使用OpenJDK(Oracle公司最鸡贼的一点是:OracleJDK最新版本是可以免费下载使用的,但是要承担相应的法律风险。如果将来等你们公司做大做强的话,Oracle公司可能会告你们侵权使用Java,是需要赔钱的(到那个时候想要胜诉几乎不可能)。毕竟曾轰动一时的Oracle公司和Google公司就Android是否侵权使用Java API一案,最终也是Google败诉,赔偿了Oracle公司合计88亿美元收尾(当年Oracle收购Sun公司也“只是”花了74亿美元而已))。


1 Java 8(LTS)

2014年3月发布

1.1 Lambda表达式和Stream API

Lambda表达式允许我们将函数当成参数传递给某个方法,或者把代码本身当作数据处理。有了Lambda表达式之后,Java语言也终于支持了函数式编程。比如我们原来可能是通过如下的匿名内部类的方式来创建一个线程:

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("thread start...");
        //...
    }
}).start();

现在有了Lambda表达式,可以简化成下面的写法:

new Thread(() -> {
    System.out.println("thread start...");
    //...
}).start();

而Stream API一般是配合Lambda表达式来一起进行使用的,比如说我现在想对一个集合中的所有元素转成大写,按照以前的写法可能是这样的:

List list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("hello");

List returnList = new ArrayList<>();
for (String string : list) {
    returnList.add(string.toUpperCase());
}

而用了Stream API之后可以这么写:

List list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("hello");

List returnList = list.stream().map(string -> string.toUpperCase()).collect(Collectors.toList());

Stream API已经集成到了Collections API中,一些常用的Stream API的用法可以查看我的另一篇文章《Stream API之常用操作》,更多的用法请查看官方文档。

1.2 方法引用

方法引用的标志是“::”、两个冒号,它可以使调用方法写起来更加简便,一般也是和Stream API来搭配使用。例如上面转大写的Stream API的写法还可以进一步简化成使用方法引用的版本:

List returnList = list.stream().map(String::toUpperCase).collect(Collectors.toList());

如果我想要遍历打印一个集合的所有元素的话,有了方法引用后不用再像以前一样写一个for循环来逐个打印,可以使用下面的简便写法:

returnList.forEach(System.out::println);

1.3 接口中的默认方法和静态方法

在Java 8之前,接口中就只能写一些接口方法,没有实现。而在Java 8中,还可以写默认方法和静态方法:

public interface InterfaceTest {

    default String defaultTest() {
        return "defaultTest";
    }

    static String staticTest() {
        return "staticTest";
    }
}

1.4 新的Date/Time API

过往在使用Date和Calendar类时一直存在着一些问题(线程不安全)和缺陷。所以在Java 8中,新添加了一些时间和日期的API:Clock、LocalDate、LocalTime、LocalDateTime、ZonedDateTime和Duration等。

1.5 Optional

在之前,我们可能需要写很多的空指针异常判断的代码,例如对一个集合判断是否为空:

if (list == null) {
    list = new ArrayList<>();
}

而有了Optional类之后,可以简化写法:

list = Optional.ofNullable(list).orElseGet(ArrayList::new);

Optional类更多的用法请查看官方文档。

1.6 JUC包下的变动

新的读写锁:StampedLock(相比于ReentrantReadWriteLock多了一种乐观读的功能);新的计数器:LongAdder(相比于AtomicLong在高并发场景下性能更高);新的异步调用类:CompletableFuture(提供了函数式编程的能力,可以通过回调的方式处理计算结果,而不是Future接口的阻塞获取方式),以及其他新添加的类等等。

1.7 HashMap和ConcurrentHashMap的变动

在Java 8中,对HashMap和ConcurrentHashMap做了性能上的改进,引入了红黑树结构,在ConcurrentHashMap中去掉了分段锁,整体结构上和Java 8中的HashMap一致。同时解决了在高并发场景下使用HashMap可能会导致链表死链,从而一直在等待的情况发生。


2 Java 9

2017年9月发布

2.1 接口中的私有方法

除了在Java 8中添加的接口中的默认方法和静态方法外,Java 9中新添加了私有方法:

public interface InterfaceTest {

    private String privateTest() {
        return "privateTest";
    }
}

可以看到,从Java 9开始,接口和抽象类的区别越来越小了,貌似只剩下了类能实现多个接口但不能多重继承的这一个区别了。

2.2 改进try-with-resources

在Java 7中添加了try-with-resources特性,可以将资源写在try语句中,从而不用再显式地调用close方法来关闭资源:

try (InputStream in = new FileInputStream(new File("D:\\read.txt"))) {
    byte[] buf = new byte[1024];
    int length;
    while ((length = in.read(buf)) != -1) {
        System.out.println(new String(buf, 0, length));
    }
} catch (IOException e) {
    e.printStackTrace();
}

而在Java 9中,做了进一步的改进:可以在try之前进行创建,而在try之中进行引用就行了,一样可以自动关闭资源:

InputStream in = new FileInputStream(new File("D:\\read.txt"));
try (in) {
    byte[] buf = new byte[1024];
    int length;
    while ((length = in.read(buf)) != -1) {
        System.out.println(new String(buf, 0, length));
    }
} catch (IOException e) {
    e.printStackTrace();
}

2.3 改进钻石操作符

钻石操作符同样是在Java 7中引入的,在Java 9中,匿名内部类也可以使用钻石操作符了:

List list = new ArrayList<>() {
    @Override
    public int size() {
        return super.size();
    }

    @Override
    public String toString() {
        return super.toString();
    }
};

2.4 Collections API

Collections API中新添加了创建不可修改集合的方法:List.of、Set.of和Map.of。

2.5 Stream API

在Stream API中新添加了一些方法:takeWhile(从Stream中获取满足条件的元素,直到不满足为止,后面即使有满足的元素也丢弃)、dropWhile(从Stream中依次删除满足条件的元素,直到不满足为止停止删除)、ofNullable(如果Stream为null,创建一个空的 Stream,避免抛出空指针异常和iterate(T, UnaryOperator)(新的重载方法)

2.6 不能使用单独下划线作为变量名

在Java 9之前,是可以使用单独下划线作为变量名的,例如下面这样:

String _ = "test";

而从Java 9开始,单独一个下划线被作为了关键字,所以以后不能再这么命名了。


3 Java 10

2018年3月发布

3.1 var关键字

在Java 10中,终于可以像在JavaScript一样来使用var关键字了,类型可以自动推断出来。例如使用局部变量的时候:

var list = new ArrayList<>();

3.2 Optional API

Optional类中添加了新的orElseThrow()空参数重载方法。

3.3 Collections API

除了Java 9中添加的新方法外,在Java 10中Collections API中又添加了一些创建不可修改集合的方法:List.copyOf、Set.copyOf和Map.copyOf,以及Stream API中的新方法:toUnmodifiableList,toUnmodifiableSet和toUnmodifiableMap。

3.4 ByteArrayOutputStream API

添加了新的重载方法toString(Charset),通过使用指定的字符集编码,将缓冲区的内容转换为字符串。

3.5 PrintStream、PrintWriter、Scanner API

PrintStream、PrintWriter和Scanner类中各添加了一些带Charset参数的新构造器方法。

3.6 Reader API

Reader类中新添加了transferTo方法(从这个Reader中读取所有字符串,并按照所读取的顺序将字符串写入到指定的Writer


4 Java 11(LTS)

2018年9月发布

4.1 增强var关键字

在Java 10中,var关键字只能用在局部变量上。而在Java 11中,var关键字可以用在Lambda表达式中:

(@Nonnull var x, @Nullable var y) -> x.process(y)

4.2 Collections API

Collections API中添加了新的重载方法toArray(IntFunction)。

4.3 String API

String类中添加了一些新的方法:strip(去除字符串首尾中的空白字符,相比trim,stip对于全角空白字符也可以去除)、stripLeading(去除字符串首部的空白字符)、stripTrailing(去除字符串尾部的空白字符)、isBlank(判断字符串是否是空白字符)、lines(返回一个通过换行符(\n、\r、\r\n)分隔后的Stream)和repeat(复制字符串)

4.4 删除Thread.destroy()和Thread.stop(Throwable)方法

一直以来,destroy和stop方法都是标注为过时的。在Java 11中,终于去掉了这两个方法,但是空参数的stop()方法并没有去除。

你可能感兴趣的:(Java基础,Java,8-11新特性)