java各版本 新特性_Java9到Java13各版本新特性代码全部详解(全网独家原创)

Java现在已经发展到了Java13了(正式版本),相信很多朋友还对各个版本还不是很熟悉,这里面专门把Java9到Java13各个版本的一些新特性做了一些详细讲解。我在网上也找了很多,但基本都是官方文档的CV,没有任何代码演示,而且官方的示例代码也不是很好找得到,官方API目前还是Java10,官方文档真是坑啊。所以我在这里专门写了一篇文章,主要针对平时开发与有关的功能Java9到Java13各个版本都做了代码详细讲解。

【PS】:这个季节太冷了,南方湿冷,我的手都生冻疮了,看在年前最后几天了,没办法,我最后选择去网吧花了几天时间,网费都花了好几百块,为了打造这篇干货不惜下血本啊。终于奋战几天写出来了这篇文章。每一个语法细节都经过实例演示过的,我特意把每个版本的Open JDK都下载了一遍,体验里面的细节差距和新特性。

希望大家点赞,评论和收藏三连,也不负我的一片苦心,谢谢大家了。

想获得更多干货,欢迎大家多多关注我的博客。本文为作者AWeiLoveAndroid原创,未经授权,严禁转载。

6370c6cf4481de86c8e5f0c0a255f585.png

文章目录

一、Java 9Java 9 集合工厂方法REPL (JShell)接口支持私有方法和私有静态方法:改进的 Stream API和Optional 类改进的 CompletableFuture API异常处理机制改进try-with-resources改进的 @Deprecated 注解钻石操作符(Diamond Operator“”)Unicode 7.0扩展支持:二、Java 10var 局部变量类型推断支持Unicode 8.0。三、Java 11局部变量的语法lambda参数启动单文件源代码程序四、Java 12对 switch 语句进行扩展:五、Java 13switch表达式预览版Text Blocks预览版(文字块)

一、Java 9

【注:】Java9的更新是最多的,这个需要特别注意学一下。

Java 9 集合工厂方法

示例:

public static void main(String[] args) { Set set = Set.of("set1", "set2", "set3"); // set: [set1, set3, set2] System.out.println("set: " + set); Map maps1 = Map.of( "map1","Apple", "map2","Orange","map3","Banana", "map4","cherry"); // maps1: {map3=Banana, map2=Orange, map1=Apple, map4=cherry} System.out.println("maps1: " + maps1); Map maps2 = Map.ofEntries ( new AbstractMap.SimpleEntry("map1","Apple"), new AbstractMap.SimpleEntry("map2","Orange"), new AbstractMap.SimpleEntry("map3","Banana"), new AbstractMap.SimpleEntry("map4","cherry"), new AbstractMap.SimpleEntry("map5","Apple"), new AbstractMap.SimpleEntry("map6","Orange"), new AbstractMap.SimpleEntry("map7","Banana"), new AbstractMap.SimpleEntry("map8","cherry"), new AbstractMap.SimpleEntry("map9","Apple"), new AbstractMap.SimpleEntry("map10","Orange"), new AbstractMap.SimpleEntry("map11","Banana"), new AbstractMap.SimpleEntry("map12","cherry") ); // maps2: {map3=Banana, map2=Orange, map1=Apple, map12=cherry, map11=Banana, map10=Orange, // map9=Apple, map8=cherry, map7=Banana, map6=Orange, map5=Apple, map4=cherry} System.out.println("maps2: " + maps2);}Java9以前的做法:

List list = new ArrayList();list.add("A");list.add("B");list.add("C");Set set = new HashSet();set.add("A");set.add("B");set.add("C");Map map = new HashMap();map.put("A","Apple");map.put("B","Boy");map.put("C","Cat");Java9可以直接输出集合的内容,在此之前必须遍历集合才能全部获取里面的元素。这是一个很大的改进。

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

Java 9 中,可以使用以下方法创建 List,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)static Set of()static Set of(E e1)static Set of(E e1, E e2)static Set of(E e1, E e2, E e3)static Set of(E e1, E e2, E e3, E e4)static Set of(E e1, E e2, E e3, E e4, E e5)static Set of(E e1, E e2, E e3, E e4, E e5, E e6)static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7)static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8)static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9)static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)static Set of(E... elements)static Map of() static Map of(K k1, V v1)static Map of(K k1, V v1, K k2, V v2)static Map of(K k1, V v1, K k2, V v2, K k3, V v3)static Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4)static Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5)static Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6)static Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7)static Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8)static Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9)static Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10)static Map ofEntries(Entry extends K, ? extends V>... entries)List ,Set 和Map 接口, of(…) 方法重载了 0 ~ 10 个参数的不同方法 。Map 接口如果超过 10 个参数, 可以使用 ofEntries(…) 方法。

REPL (JShell)

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

例如:

输入“jshell”打开jshell命令窗口:

142405b0b3420b8e895c971f269900aa.png

输入“/help”查看帮助信息:

1fd046fcc8ed1d5eeebac05040ffee73.png

进行运算,创建和使用函数,以及退出:

e7759031c45f03e832fa1904ea07f35d.png

接口支持私有方法和私有静态方法:

下图是Java8和java9的接口的变化的对比:

5d0056212f5c925235eca047362866b8.png

示例如下:

interface Test{ String fields = "interface field"; public abstract void abstractMethods(); default void defaultMethods() { System.out.println("default Method"); staticMethods(); privateMethods(); privateStaticMethods(); } static void staticMethods() { System.out.println("static Method"); } private void privateMethods() { System.out.println("private Method"); } private static void privateStaticMethods() { System.out.println("private Static Method"); } }接口实现类:

public class TestImpl implements Test{ @Override public void abstractMethods() { System.out.println("abstract Method"); } }测试类:

public class Demo{ public static void main(String[] args) { TestImpl testImpl = new TestImpl(); System.out.println(testImpl.fields); testImpl.abstractMethods(); testImpl.defaultMethods(); }}测试结果:

interface fieldabstract Methoddefault Methodstatic Methodprivate Methodprivate Static Method改进的 Stream API和Optional 类

Java 9 改进的 Stream API ,为 Stream 新增了几个方法:dropWhile、takeWhile、ofNullable,为 iterate 方法新增了一个重载方法,使流处理更容易。

Optional 类在Java8中引入,它的引入很好的解决空指针异常,在 java 9 中, 添加了stream(),ifPresentOrElse()和or()三个方法来改进它的功能。

示例如下:

Stream.of("a","b","c","","e","f").takeWhile(s->!s.isEmpty()) .forEach(System.out::print);System.out.println();Stream.of("10","20","30","","40","50").dropWhile(s-> !s.isEmpty()) .forEach(System.out::print);System.out.println();IntStream.iterate(3, x -> x x+ 3).forEach(System.out::print);System.out.println();System.out.println(Stream.ofNullable(100).count());System.out.println(Stream.ofNullable(null).count());结果:

// abc// 4050// 369// 1// 0public static void main(String[] args) { // stream()用法: List> list = Arrays.asList ( Optional.of("data1"), Optional.empty(), Optional.of("data2"), Optional.empty(), Optional.of("data3")); List result = list.stream() .flatMap(Optional::stream) .collect(Collectors.toList()); // 结果 [data1, data2, data3] System.out.println(result); // ifPresentOrElse使用: Optional optional = Optional.of("datas"); // 结果 Value: datas optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() -> System.out.println("No data found")); optional = Optional.empty(); // 结果 No data found optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() -> System.out.println("No data found")); Optional optional1 = Optional.of("datas"); Supplier> nullData = () -> Optional.of("No data found"); optional1 = optional1.or(nullData); // Value: datas optional1.ifPresent( x -> System.out.println("Value: " + x)); optional1 = Optional.empty(); optional1 = optional1.or(nullData); // Value: No data found optional1.ifPresent( x -> System.out.println("Value: " + x));}改进的 CompletableFuture API

支持 delays 和 timeouts,提升了对子类化的支持,新的工厂方法:

public CompletableFuture completeOnTimeout(T value, long timeout, TimeUnit unit):在timeout(单位在java.util.concurrent.Timeunits units中,比如 MILLISECONDS )前以给定的 value 完成这个 CompletableFutrue。返回这个 CompletableFutrue。

public CompletableFuture orTimeout(long timeout, TimeUnit unit):如果没有在给定的 timeout 内完成,就以 java.util.concurrent.TimeoutException 完成这个 CompletableFutrue,并返回这个 CompletableFutrue。

public CompletableFuture newIncompleteFuture():使得CompletableFuture可以被更简单的继承

CompletionStage completedStage(U value):返回一个新的以指定 value 完成的CompletionStage ,并且只支持 CompletionStage 里的接口。

CompletionStage failedStage(Throwable ex):返回一个新的以指定异常完成的CompletionStage ,并且只支持 CompletionStage 里的接口。

异常处理机制改进try-with-resources

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

示例如下:

public static void main(String[] args) throws IOException { System.out.println(readData("test"));// 结果:test}static String readData(String message) throws IOException { Reader inputString = new StringReader(message); BufferedReader br = new BufferedReader(inputString); // Java8处理方式: // try (BufferedReader br1 = br) { // return br1.readLine(); // } // Java9处理方式: try (br) { return br.readLine(); }}改进的 @Deprecated 注解

Java 9 中注解增加了两个新元素:since和forRemoval。since: 元素指定已注解的API元素已被弃用的版本。forRemoval: 元素表示注解的 API 元素在将来的版本中被删除,应该迁移 API。示例如下:

@Deprecated(since = "1.9", forRemoval = true)class Test{}钻石操作符(Diamond Operator“”)

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

示例:

public class Test { public static void main(String[] args) { Handler 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 { public T content; public Handler(T content) { this.content = content; } abstract void handle();}在java8中,上例中的 newHandler后面的里面必须带有泛型类型。Java9就不需要了。

Unicode 7.0扩展支持:

从Java SE 9,升级现有平台的API,支持7.0版本的Unicode标准,主要在以下类中:

java.lang.Character和java.lang.Stringjava.text包中的Bidi,BreakIterator和Normalizer此次升级将包括改善双向行为,从而可以更好地显示Unicode 6.3中引入的阿拉伯语和希伯来语等文本。 Unicode 7.0本身将添加大约三千个字符和二十多个脚本。

更多详情请查看:https://openjdk.java.net/projects/jdk9/

二、Java 10

这里重点看我们开发者能够直接体验到的一些功能:

var 局部变量类型推断

示例:

var list = new ArrayList(); // 代表 ArrayListvar stream = list.stream(); // 代表 Stream这种处理将仅限于带有初始值设定项的局部变量,增强的for循环中的索引以及在传统的for循环中声明的局部变量。它不适用于方法形式,构造函数形式,方法返回类型,字段,catch形式或任何其他类型的变量声明。

支持Unicode 8.0。

增强了java.util.Locale和相关的API,以实现BCP 47语言标签的其他Unicode扩展。

此次针对BCP 47语言标签扩展包括:

cu (货币类型)fw (一周的第一天)rg (区域覆盖)tz (时区)具体API变更有:

java.text.DateFormat::get*Instance将根据扩展名返回实例ca,rg和/或tzjava.text.DateFormatSymbols::getInstance 将根据扩展名返回实例 rgjava.text.DecimalFormatSymbols::getInstance 将根据扩展名返回实例 rgjava.text.NumberFormat::get*Instance将根据扩展名nu和/或返回实例rgjava.time.format.DateTimeFormatter::localizedBy将返回DateTimeFormatter基于扩展情况下ca,rg和/或tzjava.time.format.DateTimeFormatterBuilder::getLocalizedDateTimePattern将根据rg扩展名返回模式字符串。java.time.format.DecimalStyle::of将DecimalStyle根据扩展名返回实例nu,和/或rgjava.time.temporal.WeekFields::of将WeekFields根据扩展名fw和/或返回实例rgjava.util.Calendar::{getFirstDayOfWeek,getMinimalDaysInWeek}将根据扩展名fw和/或返回值rgjava.util.Currency::getInstance将Currency根据扩展名cu和/或返回实例rgjava.util.Locale::getDisplayName 将返回一个字符串,其中包括这些U扩展名的显示名称java.util.spi.LocaleNameProvider 这些U扩展的键和类型将具有新的SPI其他特性都是有关垃圾回收,编译器,证书,以及命令工具等有关的,这里就不列举了。

更多详情请查看:https://openjdk.java.net/projects/jdk/10/

三、Java 11

局部变量的语法lambda参数

Java11中的lambda表达式可以为隐式类型,其中类型的形式参数都可以被推断出。对于隐式类型的lambda表达式的形式参数,允许使用保留的类型名称var,以便:(var x, var y) -> x.process(y)等效于:

(x, y) -> x.process(y) // 这样的对的(var x, int y) -> x.process(y) // 这样就会报错其他的lambda用法和Java8里的lambda用法一样。

启动单文件源代码程序

增强java启动器以运行作为Java源代码的单个文件提供的程序,包括通过“ shebang”文件和相关技术从脚本内部使用该程序。

从JDK 10开始,java启动器以三种模式运行:启动类文件,启动JAR文件的main类或启动模块的main类。在这里,我们添加了新的第四种模式:启动在源文件中声明的类。

如果“类名”标识具有.java扩展名的现有文件,则选择源文件模式,并编译和运行该文件。该–source选项可用于指定源代码的源版本。

如果文件没有.java扩展名,则–source必须使用该选项来强制源文件模式。例如当源文件是要执行的“脚本”并且源文件的名称不遵循Java源文件的常规命名约定时。

更多详情请查看:https://openjdk.java.net/projects/jdk/11/

四、Java 12

对 switch 语句进行扩展:

扩展switch语句,以便可以将其用作语句或表达式,并且两种形式都可以使用“传统”或“简化”作用域并控制流的行为。这些变化将简化日常编码在switch中。这是JDK 12中的预览功能。

请注意:此JEP已被JDK 13的JEP 354取代。

普通写法:

switch (day) { case MONDAY: case FRIDAY: case SUNDAY: System.out.println(6); break; case TUESDAY: System.out.println(7); break; case THURSDAY: case SATURDAY: System.out.println(8); break; case WEDNESDAY: System.out.println(9); break;}现在引入一种新的switch标签形式,写为“case L ->”,表示如果匹配标签,则只执行标签右边的代码。例如,现在可以编写以前的代码:

switch (day) { case MONDAY, FRIDAY, SUNDAY -> System.out.println(6); case TUESDAY -> System.out.println(7); case THURSDAY, SATURDAY -> System.out.println(8); case WEDNESDAY -> System.out.println(9);}再比如局部变量,普通写法是这样的:

int numLetters;switch (day) { case MONDAY: case FRIDAY: case SUNDAY: numLetters = 6; break; case TUESDAY: numLetters = 7; break; case THURSDAY: case SATURDAY: numLetters = 8; break; case WEDNESDAY: numLetters = 9; break; default: throw new IllegalStateException("Wat: " + day);}现在的写法是这样的:

int numLetters = switch (day) { case MONDAY, FRIDAY, SUNDAY -> 6; case TUESDAY -> 7; case THURSDAY, SATURDAY -> 8; case WEDNESDAY -> 9;};更多详情请查看:https://openjdk.java.net/projects/jdk/12/

五、Java 13

switch表达式预览版

JDK 13中新增 switch 表达式beta 版本,这是对Java12 switch表达式功能的增强版本,并且Java13版本的switch表达式的更新可以用于生产环境中。switch 表达式扩展了 switch 语句,使其不仅可以作为语句(statement),还可以作为表达式(expression),并且两种写法都可以使用传统的 switch 语法。

除了Java12的用法之外,Java13的更新引入一个新的关键字yield。大多数switch表达式在“case L ->”开关标签的右侧都有一个表达式。如果需要一个完整的块,需要使用yield语句来产生一个值,该值是封闭switch表达式的值。

示例:

int j = switch (day) { case MONDAY -> 0; case TUESDAY -> 1; default -> { int k = day.toString().length(); int result = f(k); yield result; }};上例也可以使用传统的switch语句:

int result = switch (s) { case "Foo": yield 1; case "Bar": yield 2; default: System.out.println("Neither Foo nor Bar, hmmm..."); yield 0;};switch表达的情况必须详细;对于所有可能的值,必须有一个匹配的switch标签。(显然,switch声明并非必须详细。)这通常意味着需要一个default子句。但是enum switch对于覆盖所有已知常量的表达式,default编译器会插入一个子句以指示该enum定义在编译时和运行时之间已更改。依靠这种隐式default子句的插入可以使代码更健壮。现在,当重新编译代码时,编译器将检查所有情况是否得到明确处理。

此外,switch表达式必须以一个值正常完成,或者必须通过引发异常来突然完成。这有许多后果。首先,编译器会检查每个开关标签是否匹配,然后产生一个值。

示例:

int i = switch (day) { case MONDAY -> { System.out.println("Monday"); // ERROR! Block doesn't contain a yield statement } default -> 1;};i = switch (day) { case MONDAY, TUESDAY, WEDNESDAY: yield 0; default: System.out.println("Second half of the week"); // ERROR! Group doesn't contain a yield statement};另一种后果是,控制语句,break,yield,return和continue,无法通过跳switch表达式,示例:

z: for (int i = 0; i Text Blocks预览版(文字块)

简单地说就是:可以跨多行显示字符串并且不对转义字符进行转义。目标是编写Java程序的任务,同时避免了常见情况下的转义序列,增强Java程序中表示用非Java语言编写的代码的字符串的可读性。

在Java中,在字符串文字中嵌入HTML,XML,SQL或JSON片段"…"通常需要先进行转义和串联的大量编辑工作,然后才能编译包含该代码块的代码。该代码快通常难以阅读且难以维护。但是Java13的代码块功能会更直观地表示字符串,而且可以跨越多行,而且不会出现转义的视觉混乱,这将提高Java程序的可读性和可写性。本质上是二维文本块,而不是一维字符序列。

基本语法形式:

"""line 1line 2line 3"""等效于:"line 1\nline 2\nline 3\n"

或字符串文字的串联:

"line 1\n" +"line 2\n" +"line 3\n"如果在字符串的末尾不需要行终止符,则可以将结束定界符放在内容的最后一行。例如,文本块:

"""line 1line 2line 3"""具体使用:

字符串里面写HTML代码,

Java13之前写法:

String html = "\n" + " \n" + " Hello, world

\n" + " \n" + "\n";Java13写法:

String html = """ Hello, world

""";再比如SQL示例:

Java13之前写法:

String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" + "WHERE `CITY` = 'INDIANAPOLIS'\n" + "ORDER BY `EMP_ID`, `LAST_NAME`;\n";Java13写法:

String query = """ SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB` WHERE `CITY` = 'INDIANAPOLIS' ORDER BY `EMP_ID`, `LAST_NAME`; """; 再比如:

Java13之前写法:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");Object obj = engine.eval("function hello() {\n" + " print('\"Hello, world\"');\n" + "}\n" + "\n" + "hello();\n"); Java13写法:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");Object obj = engine.eval(""" function hello() { print('"Hello, world"'); } hello(); """);更多详情请查看:https://openjdk.java.net/projects/jdk/13/

本文转载自:https://blog.csdn.net/lzw2497727771/article/details/104019737,旨在分享技术,整合信息,若有侵权请私信,侵权必删

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值