Java9新特性:
JDK 和 JRE 目录结构的改变:
Java8目录结构:
bin 目录 包含命令行开发和调试工具, 如javac, jar和javadoc。 include目录 包含在编译本地代码时使用的C/C++头文件 lib 目录 包含JDK工具的几个JAR和其他类型的文件。 它有一个tools.jar文件, 其中包 含javac编译器的Java类 jre/bin 目录 包含基本命令, 如java命令。 在Windows平台上, 它包含系统的运行时动态链 接库(DLL) 。 jre/lib 目录 包含用户可编辑的配置文件, 如.properties和.policy文件。 包含几个JAR。 rt.jar文件包含运行时的Java类和资源文件 Java9目录结构:
没有名为jre的子目录 bin 目录 包含所有命令。 在Windows平台上, 它继续包含系统的运行时动态链接库。 conf 目录 包含用户可编辑的配置文件, 例如以前位于jre\lib目录中的.properties和.policy文件 include 目录 包含要在以前编译本地代码时使用的C/C++头文件。 它只存在于JDK中 jmods 目录 包含JMOD格式的平台模块。 创建自定义运行时映像时需要它。 它只存在于JDK中 legal 目录 包含法律声明 lib 目录 包含非Windows平台上的动态链接本地库。 其子目录和文件不应由开发人员直接编辑或使用 模块化系统: Jigsaw 到 Modularity:
模块将由通常的类和新的模块声明文件(module-info.java) 组成。
该文件是位于java代码结构的顶层, 该模块描述符明确地定义了我们的模块需要什么依赖关系,以及哪些模块被外部使用。
在exports子句中未提及的所有包默认情况下将封装在模块中, 不能在外部使用。
要想在java9demo模块中调用java9test模块下包中的结构, 需要在java9test的module-info.java中声明:
/*exports: 控制着哪些包可以被其它模块访问到。 所有不被导出的包默认都被封装在模块里面。*/ module java9test { //package we export exports com.bean; }
对应在java 9demo 模块的src 下创建module-info.java文件:
//requires:指明对其它模块的依赖。S module java9demo { requires java9test; }
Java的REPL工具: jShell命令
交互式编程环境 REPL (read - evaluate - print - loop)
jShell可以从文件中加载语句或者将语句保存到文件中。
jShell可以是tab键进行自动补全和自动添加分号。
可以重新定义相同方法名和参数列表的方法, 即为对现有方法的修改(或覆盖) 。
在 JShell 环境下, 语句末尾的“;” 是可选的。
jshell没有受检异常。
调出jshell:jshell
获取帮助:/help intro
查看已经导入的所有包:/imports
列出session里所有有效的代码片段:/list
查看session下所有创建过的变量:/vars
查看session下所有创建过的方法:/methods
使用外部编辑器来编写代码:/edit add
执行java文件:/open HelloWorld.java
退出jshell:/exit
Java9中可以接口声明私有方法。
Java9中能够与匿名实现类共同使用钻石操作符<>(diamond operator) 。
Comparator<Object> com = new Comparator<>(){ @Override public int compare(Object o1, Object o2) { return 0; } };
Java 8 中, 可以实现资源的自动关闭, 但是要求执行后必须关闭的所有资源必须在try子句中初始化, 否则编译不通过。
如下例所示:
try(InputStreamReader reader = new InputStreamReader(System.in)){ //读取数据细节省略 }catch (IOException e){ e.printStackTrace(); }
Java 9 中, 用资源语句编写try将更容易, 我们可以在try子句中使用已经初始化过的资源, 此时的资源是final的:
InputStreamReader reader = new InputStreamReader(System.in); OutputStreamWriter writer = new OutputStreamWriter(System.out); try (reader; writer) { //reader是final的,不可再被赋值 //reader = null; //具体读写操作省略 } catch (IOException e) { e.printStackTrace(); }
Java9中String,StringBuffer,StringBuilder不用 char[] 来存储, 改成了 byte[] 加上编码标记, 节约了一些空间。
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { @Stable private final byte[] value; }
集合工厂方法:快速创建只读集合
Java8中:
List<String> namesList = new ArrayList <>(); namesList.add("Joe"); namesList.add("Bob"); namesList.add("Bill"); namesList = Collections.unmodifiableList(namesList); System.out.println(namesList);
Java9中:
List<String> list = Collections.unmodifiableList(Arrays.asList("a", "b", "c")); Set<String> set = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("a","b", "c"))); // 如下操作不适用于jdk 8 及之前版本,适用于jdk 9 Map<String, Integer> map = Collections.unmodifiableMap(new HashMap<>() { { put("a", 1); put("b", 2); put("c", 3); } }); map.forEach((k, v) -> System.out.println(k + ":" + v));
List firsnamesList = List.of(“Joe”,”Bob”,”Bill”);
调用集合中静态方法of(), 可以将不同数量的参数传输到此工厂方法中。
此功能可用于Set和List, 也可用于Map的类似形式。
此时得到的集合, 是不可变的:在创建后, 继续添加元素到这些集合会导致 “UnsupportedOperationException” 。
由于Java 8中接口方法的实现, 可以直接在List, Set和Map的接口内定义这些方法,便于调用。
InputStream 加强:
InputStream 有了一个方法: transferTo,可以用来将数据直接传输到 OutputStream 。
ClassLoader cl = this.getClass().getClassLoader(); try (InputStream is = cl.getResourceAsStream("hello.txt"); OutputStream os = new FileOutputStream("src\\hello1.txt")) { is.transferTo(os); // 把输入流中的所有数据直接自动地复制到输出流中 } catch (IOException e) { e.printStackTrace(); }
增强的 Stream API:
Stream 接口中添加了 4 个新的方法:takeWhile, dropWhile, ofNullable,还有个 iterate 方法的新重载方法,可以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代。
除了对 Stream 本身的扩展, Optional 和 Stream 之间的结合也得到了改进。
现在可以通过 Optional 的新方法 stream() 将一个 Optional 对象转换为一个(可能是空的) Stream 对象。
/* takeWhile()的使用 用于从 Stream 中获取一部分数据, 接收一个 Predicate 来进行选择。 在有序的Stream 中, takeWhile 返回从开头开始的尽量多的元素。 */ List<Integer> list = Arrays.asList(45, 43, 76, 87, 42, 77, 90, 73, 67, 88); list.stream().takeWhile(x -> x < 50).forEach(System.out::println); System.out.println(); list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8); list.stream().takeWhile(x -> x < 5).forEach(System.out::println); /* dropWhile()的使用 dropWhile 的行为与 takeWhile 相反, 返回剩余的元素。 */ List<Integer> list = Arrays.asList(45, 43, 76, 87, 42, 77, 90, 73, 67, 88); list.stream().dropWhile(x -> x < 50).forEach(System.out::println); System.out.println(); list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8); list.stream().dropWhile(x -> x < 5).forEach(System.out::println); /* ofNullable()的使用 Java 8 中 Stream 不能完全为null, 否则会报空指针异常。 而 Java 9 中的 ofNullable 方法允许我们创建一个单元素 Stream, 可以包含一个非空元素, 也可以创建一个空Stream。 */ // 报NullPointerException // Stream<Object> stream1 = Stream.of(null); // System.out.println(stream1.count()); // 不报异常,允许通过 Stream<String> stringStream = Stream.of("AA", "BB", null); System.out.println(stringStream.count());// 3 // 不报异常,允许通过 List<String> list = new ArrayList<>(); list.add("AA"); list.add(null); System.out.println(list.stream().count());// 2 // ofNullable():允许值为null Stream<Object> stream1 = Stream.ofNullable(null); System.out.println(stream1.count());// 0 Stream<String> stream = Stream.ofNullable("hello world"); System.out.println(stream.count());// 1 /* iterate()重载的使用 这个 iterate 方法的新重载方法, 可以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代。 */ // 原来的控制终止方式: Stream.iterate(1, i -> i + 1).limit(10).forEach(System.out::println); // 现在的终止方式: Stream.iterate(1, i -> i < 100, i -> i + 1).forEach(System.out::println); /* Optional类中stream()的使用 */ List<String> list = new ArrayList<>(); list.add("Tom"); list.add("Jerry"); list.add("Tim"); Optional<List<String>> optional = Optional.ofNullable(list); Stream<List<String>> stream = optional.stream(); stream.flatMap(x -> x.stream()).forEach(System.out::println);
Javascript引擎升级: Nashorn
Nashorn 项目在 JDK 9 中得到改进, 它为 Java 提供轻量级的 Javascript 运行时。
Nashorn 项目跟随 Netscape 的 Rhino 项目, 目的是为了在 Java 中实现一个高性能但轻量级的 Javascript 运行时。
Nashorn 项目使得 Java 应用能够嵌入Javascript。
它在 JDK 8 中为 Java 提供一个 Javascript 引擎。
JDK 9 包含一个用来解析 Nashorn 的 ECMAScript 语法树的 API。
这个 API 使得IDE 和服务端框架不需要依赖 Nashorn 项目的内部实现类, 就能够分析ECMAScript 代码。
Java10新特性:
JDK10一共定义了109个新特性, 其中包含12个JEP (JDK Enhancement Proposal特性加强提议) 。
局部变量类型推断
//1.局部变量的初始化 var list = new ArrayList<>(); //2.增强for循环中的索引 for(var v : list) { System.out.println(v); } //3.传统for循环中 for(var i = 0;i < 100;i++) { System.out.println(i); } /* 如下情况不适用: 情况1: 没有初始化的局部变量声明 情况2: 方法的返回类型 情况3: 方法的参数类型 情况4: 构造器的参数类型 情况5: 属性 情况6: catch块,Lambda表达式,方法引用,为数组静态初始化,局部变量初始值为null */
工作原理:
在处理 var时, 编译器先是查看表达式右边部分, 并根据右边变量值的类型进行推断, 作为左边变量的类型, 然后将该类型写入字节码当中。
注意:var不是一个关键字,除了不能用它作为类名,变量名或方法名等均可使用。
var并不会改变Java是一门静态类型语言的事实。 编译器负责推断出类型, 并把结果写入字节码文件 。
自 Java 9 开始, Jdk 里面为集合(List / Set / Map) 都添加了 of (jdk9新增)和copyOf (jdk10新增)方法, 它们两个都用来创建不可变的集合, 来看下它们的使用和区别如下:
//示例1: var list1 = List.of("Java", "Python", "C"); var copy1 = List.copyOf(list1); System.out.println(list1 == copy1); // true //示例2: var list2 = new ArrayList<String>(); var copy2 = List.copyOf(list2); System.out.println(list2 == copy2); // false /* 从源码分析,可以看出copyOf方法会先判断来源集合是不是AbstractImmutableList类型的,如果是,就直接返回,如果不是,则调用of创建一个新的集合。 示例2因为用的new创建的集合,不属于不可变AbstractImmutableList类的子类,所以copyOf方法又创建了一个新的实例,所以为false。 注意:使用of和copyOf创建的集合为不可变集合,不能进行添加、删除、替换、排序等操作,不然会报java.lang.UnsupportedOperationException异常。 上面演示了List的of和copyOf方法,Set和Map接口都有。 */
Java11新特性:LTS (Long-Term-Support)
Java11 将带来 ZGC、Http Client 等重要特性, 一共包含 17 个 JEP(JDK Enhancement Proposals, JDK 增强提案) 。
JDK 11 是一个长期支持版本(LTS, Long-Term-Support)。
ZGC:能够保证不超过 10ms 的 GC 暂停。
新增了一系列字符串处理方法:
描述 举例 判断字符串是否为空白 " ".isBlank(); // true 去除首尾空白 " Javastack ".strip(); // “Javastack” 去除尾部空格 " Javastack “.stripTrailing(); // " Javastack” 去除首部空格 " Javastack ".stripLeading(); // "Javastack " 复制字符串 “Java”.repeat(3);// “JavaJavaJava” 行数统计 “A\nB\nC”.lines().count(); // 3 Optional 加强:
可以很方便的将一个 Optional 转换成一个 Stream, 或者当一个空 Optional 时给它一个替代的。
新增方法 描述 新增的版本 boolean isEmpty() 判断value是否为空 JDK 11 ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) value非空,执行参数1功能;如果value 为空,执行参数2功能 JDK 9 Optional or(Supplier<? extends Optional<? extends T>> supplier) value非空,返回对应的Optional; value为空,返回形参封装的Optional JDK 9 Stream stream() value非空,返回仅包含此value的 Stream;否则,返回一个空的Stream JDK 9 T orElseThrow() value非空,返回value;否则抛异常 NoSuchElementException JDK 10 局部变量类型推断升级:
在var上添加注解的语法格式,在JDK11中加入了这样的语法。
//错误的形式: 必须要有类型, 可以加上var //Consumer<String> con1 = (@Deprecated t) -> System.out.println(t.toUpperCase()); //正确的形式: //使用var的好处是在使用lambda表达式时给参数加上注解。 Consumer<String> con2 = (@Deprecated var t) -> System.out.println(t.toUpperCase());
全新的HTTP 客户端API:
HTTP,用于传输网页的协议,早在1997年就被采用在目前的1.1版本中。
直到2015年, HTTP2才成为标准。
HTTP/1.1和HTTP/2的主要区别是如何在客户端和服务器之间构建和传输数据。
HTTP/1.1依赖于请求/响应周期。
HTTP/2允许服务器“push”数据:它可以发送比客户端请求更多的数据。
这使得它可以优先处理并发送对于首先加载网页至关重要的数据。
这是 Java 9 开始引入的一个处理 HTTP 请求的的 HTTP Client API, 该API 支持同步和异步, 而在 Java 11 中已经为正式可用状态, 你可以在java.net 包中找到这个 API。
它 将 替 代 仅 适 用 于 blocking 模 式 的 HttpURLConnection( HttpURLConnection是在HTTP 1.0的时代创建的, 并使用了协议无关的方法) , 并提供对WebSocket 和 HTTP/2的支持。
HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder(URI.create("http://127.0.0.1:8080/test/")).build(); BodyHandler<String> responseBodyHandler = BodyHandlers.ofString(); HttpResponse<String> response = client.send(request, responseBodyHandler); String body = response.body(); System.out.println(body); HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder(URI.create("http://127.0.0.1:8080/test/")).build(); BodyHandler<String> responseBodyHandler = BodyHandlers.ofString(); CompletableFuture<HttpResponse<String>> sendAsync = client.sendAsync(request, responseBodyHandler); sendAsync.thenApply(t -> t.body()).thenAccept(System.out::println); //HttpResponse<String> response = sendAsync.get(); //String body = response.body(); //System.out.println(body);
更简化的编译运行程序:
可以直接编译运行java文件:java Javastack.java
一个命令编译运行源代码的注意点:
执行源文件中的第一个类, 第一个类必须包含主方法。
并且不可以使用其它源文件中的自定义类, 本文件中的自定义类是可以使用的。
ZGC:
GC是java主要优势之一。
然而, 当GC停顿太长, 就会开始影响应用的响应时间。
消除或者减少GC停顿时长, java将对更广泛的应用场景是一个更有吸引力的平台。
此外, 现代系统中可用内存不断增长,用户和程序员希望JVM能够以高效的方式充分利用这些内存, 并且无需长时间的GC暂停时间。
ZGC, A Scalable Low-Latency Garbage Collector(Experimental)ZGC, 这应该是JDK11最为瞩目的特性, 没有之一。
但是后面带了Experimental,说明这还不建议用到生产环境。
ZGC是一个并发, 基于region, 压缩型的垃圾收集器, 只有root扫描阶段会STW(stop the world), 因此GC停顿时间不会随着堆的增长和存活对象的增长而变长。
优势:
GC暂停时间不会超过10ms
既能处理几百兆的小堆, 也能处理几个T的大堆(OMG)
和G1相比, 应用吞吐能力不会下降超过15%
为未来的GC功能和利用colord指针以及Load barriers优化奠定基础
初始只支持64位系统
ZGC的设计目标是:
支持TB级内存容量, 暂停时间低(<10ms) , 对整个程序吞吐量的影响小于15%。
将来还可以扩展实现机制, 以支持不少令人兴奋的功能, 例如多层堆(即热对象置于DRAM和冷对象置于NVMe闪存) ,
或压缩堆。其他新特性:
Unicode 10
Deprecate the Pack200 Tools and API
新的Epsilon垃圾收集器
完全支持Linux容器(包括Docker)
支持G1上的并行完全垃圾收集
最新的HTTPS安全协议TLS 1.3
Java Flight Recorder