18.1 JDK9
1、JDK目录结构的改变
2、模块化系统
Java和相关生态在不断丰富的同时也越来越暴露出一些问题:
- Java运行环境的膨胀和臃肿。每次JVM启动的时候,至少会有30~60MB的内存架子啊,主要原因是JVM需要加载rt.jar,不管其中的类是否被classloader加载,第一步整个jar都会被JVM加载到内存当中去(而模块化可以根据模块的需要加载程序运行需要的class)。
- 每一个公共类都可以被类路径下任何其他的公共类所访问到,这样就会导致无意中使用了并不像被公开访问的API。
- 实例:
// 1、module2的module-info.java中,导出本模块需要暴露的包 module module2 { exports com.xianhuii; } // 2、module1的module-info.java中,导入需要的模块 module module1 { requires module2; } // 3、module1中的类中即可访问到module2中的类 import com.xianhuii.Person; public class ModuleTest { public static void main(String[] args) { Person person = new Person(); } }
3、Java的REPL工具:jshell
jshell> /help | 键入 Java 语言表达式, 语句或声明。 | 或者键入以下命令之一: | /list [<名称或 id>|-all|-start] | 列出您键入的源 | /edit <名称或 id> | 编辑源条目 | /drop <名称或 id> | 删除源条目 | /save [-all|-history|-start] <文件> | 将片段源保存到文件 | /open <file> | 打开文件作为源输入 | /vars [<名称或 id>|-all|-start] | 列出已声明变量及其值 | /methods [<名称或 id>|-all|-start] | 列出已声明方法及其签名 | /types [<名称或 id>|-all|-start] | 列出类型声明 | /imports | 列出导入的项 | /exit [<integer-expression-snippet>] | 退出 jshell 工具 | /env [-class-path <路径>] [-module-path <路径>] [-add-modules <模块>] ... | 查看或更改评估上下文 | /reset [-class-path <路径>] [-module-path <路径>] [-add-modules <模块>]... | 重置 jshell 工具 | /reload [-restore] [-quiet] [-class-path <路径>] [-module-path <路径>]... | 重置和重放相关历史记录 -- 当前历史记录或上一个历史记录 (-restore) | /history [-all] | 您键入的内容的历史记录 | /help [<command>|<subject>] | 获取有关使用 jshell 工具的信息 | /set editor|start|feedback|mode|prompt|truncation|format ... | 设置配置信息 | /? [<command>|<subject>] | 获取有关使用 jshell 工具的信息 | /! | 重新运行上一个片段 -- 请参阅 /help rerun | /<id> | 按 ID 或 ID 范围重新运行片段 -- 参见 /help rerun | /-<n> | 重新运行以前的第 n 个片段 -- 请参阅 /help rerun | | 有关详细信息, 请键入 '/help', 后跟 | 命令或主题的名称。 | 例如 '/help /list' 或 '/help intro'。主题: | | intro | jshell 工具的简介 | keys | 类似 readline 的输入编辑的说明 | id | 片段 ID 以及如何使用它们的说明 | shortcuts | 片段和命令输入提示, 信息访问以及 | 自动代码生成的按键说明 | context | /env /reload 和 /reset 的评估上下文选项的说明 | rerun | 重新评估以前输入片段的方法的说明
4、接口的私有方法
在Java9中,可以定义私有方法,提供给默认方法使用。
public interface MyInterface { void methodAbstract(); // 访问权限是public static void methodStativc() { // 访问权限是public System.out.println("静态方法"); } default void methodDefault() { // 访问权限是public System.out.println("默认方法"); methodPrivate(); // 调用私有方法 } private void methodPrivate() { System.out.println("私有方法"); } } public class MyInterfaceImpl implements MyInterface { @Override public void methodAbstract() { } // @Override // public void methodDefault() { // // } public static void main(String[] args) { // 接口中的静态方法只能由自己调用,接口的实现类不能调用 MyInterface.methodStativc();; MyInterfaceImpl impl = new MyInterfaceImpl(); // 实现类实例调用接口中的默认方法,如果没有重写,则可间接调用接口中的私有方法 impl.methodDefault(); // 实现类实例不能调用接口中的私有方法 } }
5、钻石操作符的语法升级
import org.junit.jupiter.api.Test; import java.util.Comparator; public class DiamondTest { @Test public void test() { // 砖石操作符与匿名内部类在Java8中不能共存(new Comparator<Object>()),在Java9可以。 Comparator<Object> com = new Comparator<>() { @Override public int compare(Object o1, Object o2) { return 0; } }; } }
6、try结构的语法升级
Java8中,可以实现资源的自动关闭,但是要求执行后必须关闭的所有资源必须在try子句中初始化,否则编译不通过。
import org.junit.jupiter.api.Test; import java.io.IOException; import java.io.InputStreamReader; public class JDKTest { /** * Java 8之前 */ @Test public void test1() { InputStreamReader reader = null; try { reader = new InputStreamReader(System.in); char[] cbuf = new char[20]; int len; while ((len = reader.read(cbuf)) != -1) { String str = new String(cbuf, 0, len); System.out.println(str); } } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * Java 8 */ @Test public void test2() { try (InputStreamReader reader = new InputStreamReader(System.in)) { char[] cbuf = new char[20]; int len; while ((len = reader.read(cbuf)) != -1) { String str = new String(cbuf, 0, len); System.out.println(str); } } catch (IOException e) { e.printStackTrace(); } } /** * Java 9 * 此时的资源(reader)是默认是常量(final)。 */ @Test public void test3() { InputStreamReader reader = new InputStreamReader(System.in); try (reader) { char[] cbuf = new char[20]; int len; while ((len = reader.read(cbuf)) != -1) { String str = new String(cbuf, 0, len); System.out.println(str); } } catch (IOException e) { e.printStackTrace(); } } }
7、String存储结构变更
- 改变:char[] —> byte[]
- String、StringBuffer、StringBuilder都变了。
- 原因:节省空间。
- Most String objects contain only Latin-1 characters. Such characters require only one byte of storage, hence half of the space in the internal char arrays of such String objects is going unused.
- Change the internal representation of the String class from a UTF-16 char array to a byte array plus an encoding-flag field.
8、集合工厂方法创建只读集合
- List、Set、Map的of()静态方法。
import org.junit.jupiter.api.Test; import java.util.*; public class JDKTest { /** * Java8 */ @Test public void test1() { List<String> nameList = new ArrayList<>(); nameList.add("aa"); nameList.add("bb"); nameList.add("cc"); // 返回的是一个只读的集合 nameList = Collections.unmodifiableList(nameList); // 返回的是一个只读的集合 List<Integer> list = Arrays.asList(1, 2, 3); } /** * Java9 */ @Test public void test2() { List<Integer> list = List.of(1, 2, 3, 4, 5); Set<Integer> integers = Set.of(1, 2, 3, 4, 5); Map<String, Integer> a = Map.of("a", 1, "b", 2); Map<String, Integer> kvMap = Map.ofEntries(Map.entry("a", 1), Map.entry("b", 2)); } }
9、InputStream加强
InputStream的新方法:transferTo()。
直接把输入流中的所有数据直接自动地赋值到输出流中。
import org.junit.jupiter.api.Test; import java.io.*; public class JDKTest { @Test public void test1() { ClassLoader classLoader = this.getClass().getClassLoader(); try (InputStream is = classLoader.getResourceAsStream("hello.txt"); OutputStream os = new FileOutputStream("hello1.txt")) { is.transferTo(os); // 把输入流中的所有数据直接自动地赋值到输出流中 } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
10、增强的Stream API
Stream接口中添加了4个新的方法:takeWhile、dropWhile、ofNullable、以及iterate的重载方法。
takeWhile():返回从开头开始的按照指定规则尽量多的元素
dropWhile():与takeWhile相反,返回剩余的元素。
ofNullable():可以创建单个null值。
iterate():自定义终止条件。
import org.junit.jupiter.api.Test; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class JDKTest { @Test public void test1() { List<Integer> list = Arrays.asList(23, 41, 534, 543, 23, 12, 43); list.stream().takeWhile(i -> i < 100).forEach(System.out::println); // 23, 41 System.out.println("+++++++++++++++++++"); list.stream().dropWhile(i -> i < 100).forEach(System.out::println); // 534, 543, 23, 12, 43 System.out.println("+++++++++++++++++++"); // of()参数中的多个元素,可以包含null值, Stream<Integer> integerStream = Stream.of(1, 2, 3, null); integerStream.forEach(System.out::println); // Stream<Object> objectStream = Stream.of(null); // of()参数不能存储单个null,× // objectStream.forEach(System.out::println); // 此处会报异常 Stream<Object> objectStream2 = Stream.of(null, null); // of()参数可以包含多个null,√ Stream<Object> objectStream1 = Stream.ofNullable(null); // ofNullable()可以创建单个null值,√ System.out.println(objectStream1.count()); // 0 System.out.println("+++++++++++++++++++"); Stream.iterate(0, x -> x < 100, x -> x+1).forEach(System.out::print); } }
11、Optional的新方法:stream()
import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.stream.Stream; public class JDKTest { @Test public void test1() { List<String> list = new ArrayList<>(); list.add("aaa"); list.add("bbb"); list.add("ccc"); Optional<List<String>> optional = Optional.ofNullable(list); Stream<List<String>> stream = optional.stream(); stream.flatMap(x -> x.stream()).forEach(System.out::println); } }
12、JavaScript引擎升级:Nashorn
- JDK 9包含一个用来解析Nashorn的ECMAScript的语法树的API。这个API使得IDE和服务端框架不需要依赖Nashorn项目的内部实现类,就能分析ECMAScript代码。
18.2 JDK10
1、Local-Variable Type Inference(局部变量类型推断)
- 局部变量的显示类型声明,常常被认为是不必须的,给一个好听的名字经常可以清楚地表达出下面应该怎样继续。
- 减少了啰嗦和形式的代码,避免了信息冗余,而且对其了变量名,更容易阅读。
- 工作原理:在处理var时,编译器先是查看表达式右边部分,并根据右边变量值的类型进行推断,作为左边变量的类型,然后将该类型写入字节码当中。
- 注意:
- var不是一个关键字:除了不能用它作为类名,其他都可以。
- 这不是JavaScript:var并不会改变Java是一门静态类型语言的事实。编译器负责推断出类型,并把结果写入字节码文件,就好像是开发人员自己敲入类型一样。
2、集合中新增copyOf(),用于创建一个只读的集合
- copyOf(Xxx coll):
- 如果参数coll本身就是一个只读集合,则copyOf()返回值即为coll。
- 如果参数coll不是一个只读集合,则copyOf()返回一个新的集合,这个集合是可读的。
18.3 JDK11
- JDK11是一个长期支持版本(LTS,Long-Term-Support)。
1、String新增的方法
import org.junit.jupiter.api.Test; public class JDKTest { @Test public void test1() { // isBlank():判断字符串是否为空白 System.out.println(" ".isBlank()); // true System.out.println("\t \n ".isBlank()); // true // strip():去除首尾空白 System.out.println("\t abc \n ".strip()); // "abc" System.out.println("\t abc \n ".trim()); // "abc" // stripTrailing():去除尾部空格 System.out.println("\t abc \t \n ".stripTrailing()); // " abc" // stripLeading():去除首部空格 System.out.println("\t abc \t \n ".stripLeading()); // "abc " // repeat(int count):复制count次 String str1 = "abc"; String str2 = str1.repeat(5); System.out.println(str2); // "abcabcabcabcabc" // lines().count():行数统计 String str3 = "\n\n\n"; System.out.println(str3.lines().count()); // 3 } }
2、Optional加强
import org.junit.jupiter.api.Test; import java.util.Optional; public class JDKTest { @Test public void test1() { Optional<Object> op = Optional.empty(); System.out.println(op.isPresent()); // 判断内部的value是否存在 System.out.println(op.isEmpty()); // 判断内部的value是否为空 op = Optional.of("abc"); var obj = op.orElseThrow(); // value非空,返回value;否则抛异常:NoSuchElementException System.out.println(obj); Optional<String> op1 = Optional.of("hello"); // or:value非空,返回对应的Optional;value为空,返回形参封装的Optional Optional<Object> op2 = op.or(() -> op1); System.out.println(op2); } }
3、全新的HTTP客户端API
- HttpClient替换原有的HttpURLConnection。
4、更简化的编译运行程序
// 之前 javac Test.java java Test // JDK11 java Test.java
要求:
- 执行源文件中的第一个类,第一个类中必须要有main方法。
- 第一个类可以不是public的(类名与源文件名不同)。
- 在源文件中的,不可以引用其他源文件的类。即当前源文件中的类只能使用本文件中的类。
5、废弃Nashorn引擎。
6、ZGC
- ZGC,A Scalable Low-Latency Garbage Collector(Experimental)。