第十七章:Java9&10&11新特性

2021313

21:20

JDK9开始,目录结构的改变

bin 
JDK_HOME 
include 
bin 
jre 
lib 
」 DK8 的 目 录 结 构 
bin 目 录 
include 目 录 
lib 目 录 
jre/bin 目 录 
jre/lib 目 录 
包 含 命 令 行 开 发 和 调 试 工 具 , 如 •avac , jar 和 javadoco 
包 含 在 编 译 本 地 代 码 时 使 用 的 C / C + + 头 文 件 
包 含 JDK 工 具 的 几 个 JAR 和 其 他 类 型 的 文 件 。 它 有 一 个 to 。 《 s . jar 文 件 , 其 中 包 
含 . 编 译 器 的 Java 类 
JavaC 
包 含 基 本 命 令 , 如 java 命 令 。 在 Windows 平 台 上 , 它 包 含 系 统 的 运 行 时 动 态 链 
接 库 (DLL) 。 
包 含 用 户 可 编 辑 的 配 置 文 件 , 如 .properties 和 .policy 文 件 。 包 含 几 个 JAR 。 
jar 文 件 包 含 运 行 时 的 Java 类 和 资 源 文 件 。

 

JDK_HOME 
№ 
没 有 名 为 ] re 的 子 目 录 
bin 目 录 
conf 目 录 
include 目 录 
jmods 目 录 
legal 目 录 
№ 目 录 
conf 
include 
jmods 
legal 
lib 
JDK9 的 目 录 结 构 
包 含 所 有 命 令 。 在 Win ws 平 台 上 , 它 继 续 包 含 系 统 的 运 行 时 动 态 链 接 库 。 
包 含 用 户 可 编 辑 的 配 置 文 件 , 例 如 以 前 位 于 jre\lib 目 录 中 的 .propertes 和 .policy 文 件 
包 含 要 在 以 前 编 译 本 地 代 码 时 使 用 的 C ℃ + + 头 文 件 。 它 只 存 在 于 JDK 中 
包 含 JMOD 格 式 的 平 台 模 块 。 创 建 自 定 义 运 行 时 映 像 时 需 要 它 。 它 只 存 在 于 JDK 中 
包 含 法 律 声 明 
包 含 非 Windows 平 台 上 的 动 态 链 接 本 地 库 。 其 子 目 录 和 文 件 不 应 由 开 发 人 员 直 接 编 辑 或 使 用

 

模块化系统: Jigsaw → Modularity

模块将由通常的类和新的模块声明文件(module-info.java)组成。该文件是位于java代码结构的顶层,该模块描述符明确地定义了我们的模块需要什么依赖关系,以及哪些模块被外部使用exports子句中未提及的所有包默认情况下将封装在模块中,不能在外部使用。

 

要想在java9demo模块中调用java9test模块下包中的结构,需要在java9testmodule-info.java中声明:

module java9test {

exports com.atguigu.bean;

}

exports:控制着哪些包可以被其它模块访问到。所有不被导出的包默认都被封装在模块里面。

 

对应在java 9demo 模块的src 下创建module-info.java文件:

module java9demo {

     requires java9test;

     requires junit;

 

     exports com.atguigu.java;

}

requires:指明对其它模块的依赖。

 

JavaREPL工具: jShell命令

/help 获取帮助

/imports 查看已经导入的包

/list 列出当前 session 里所有有效的代码片段

/vars 查看当前 session 下所有创建过的变量

/methods 查看当前 session 下所有创建过的方法

Tips:我们还可以重新定义相同方法名和参数列表的方法,即为对现有方法的修改(或覆盖)。

/edit 使用外部代码编辑器来编写 Java 代码

/edit 方法名 使用外部代码编辑器来编写指定的部分

/open 文件 调用文件里的代码

Exit 退出jShell

Tab键 可自动补全代码

Tips:在 JShell 环境下,语句末尾的“;” 是可选的。但推荐还是最好加上。提高代码可读性。

没有受检异常(编译时异常)。说明:本来应该强迫我们捕获一个IOException,但却没有出现。因为jShell在后台为我们隐藏了。

 

JDK9语法改进:接口的私有方法

Java 8中规定接口中的方法除了抽象方法之外,还可以定义静态方法和默认的方法。一定程度上,扩展了接口的功能,此时的接口更像是一个抽象类。

Java 9中,接口更加的灵活和强大,连方法的访问权限修饰符都可以声明为private的了,此时方法将不会成为你对外暴露的API的一部分。

复习:

接口中方法的权限修饰符都是public

接口中的静态方法只能由接口自己调用,接口的实现类不能调用接口的静态方法,会提示:

Static method may be invoked on containing interface class only

接口中的默认方法实现类的对象可以直接调用,也可以重写。

 

jdk 9中允许接口中定义私有的方法,接口的私有方法,不能在接口外部调用,提示:'methodPrivate()' has private access in 'com.atguigu.java.MyInterface'

 

语法改进:钻石操作符使用升级

我们将能够与匿名实现类共同使用钻石操作符diamond operator

Java 8中如下的操作是会报错的:

Comparator<String> com = new Comparator<>() {

    @Override

    public int compare(String o1, String o2) {

        return 0;

    }

};

Java 9中如上操作就可以正常执行通过

 

语法改进:try语句

//java 8之前的资源关闭的操作

InputStreamReader isr = null;

try {

    isr = new InputStreamReader(System.in);

    char[] buffer = new char[20];

    int len;

    if ((len = isr.read(buffer)) != -1) {

        System.out.println(len);

        String str = new String(buffer,0,len);

        System.out.println(str);

    }

} catch (IOException e) {

    e.printStackTrace();

} finally {

    if (isr != null) {

        try {

            isr.close();

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

}

//java 8中资源关闭操作: Java 8 中,可以实现资源的自动关闭

//要求自动关闭的资源的实例化必须放在try的一对小括号中

//多个资源之间用;分号隔开

try(InputStreamReader isr = new InputStreamReader(System.in); OutputStreamWriter osw = new OutputStreamWriter(System.out)){

    char[] buffer = new char[20];

    int len = 0;

    if ((len = isr.read(buffer)) != -1) {

        osw.write(buffer,0,len);

    }

} catch (IOException e) {

    e.printStackTrace();

}

//java9中资源关闭操作:需要自动关闭的资源的实例化可以放在try的一对小括号外。

//此时的资源属性是常量,声明为final的,不可修改

//多个资源之间用;分号隔开

InputStreamReader isr = new InputStreamReader(System.in);

OutputStreamWriter osw = new OutputStreamWriter(System.out);

try(isr;osw){

    char[] buffer = new char[20];

    int len;

    if((len = isr.read(buffer)) != -1){

        osw.write(buffer,0,len);

    }

} catch (IOException e) {

    e.printStackTrace();

}

 

String存储结构变更

String 再也不用 char[] 来存储啦,改成了 byte[] 加上编码标记,节约了一些空间。

同时,与String相关的,StringBufferStringBuilder也变了

 

集合工厂方法:快速创建只读集合

java8中创建只读集合:

Collections.unmodifiableList(List l) 返回一个只读集合,不可增加,不可修改(原集合不变)

List<String> list = Collections.unmodifiableList(Arrays.asList("a", "b", "c"));

Set<String> set = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("a", "b", "c")));

Map<String,Integer> map = Collections.unmodifiableMap(new HashMap<String,Integer>(){

    {

        put("a", 1);

        put("b", 2);

    }

});

解读:

List<String> list1 = new ArrayList<>(){

    {

        add("a");

        add("b");

    }

};

System.out.println(list1.getClass()); //class com.atguigu.java.Java9Test1$2

System.out.println(list1.getClass().getSuperclass()); //class java.util.ArrayList

 

这种写法,是创建了一个ArrayList的匿名子类的对象,然后用代码块的形式调用继承的add()方法添加了两个元素

 

类似于下面这种:

Comparator com = new Comparator() {

    //代码块

    {

        System.out.println("这是一个匿名子类的代码块");

        show(); //调用匿名子类的方法

    }

    @Override

    public int compare(Object o1, Object o2) {

        return 0;

    }

    public void show(){

        System.out.println("匿名子类的方法");

    }

};

Arrays.asList(1,2,3,4,5) 此时得到的集合list也是一个只读集合。不可增加,可以修改

java9新特性:集合工厂方法:创建只读集合。不可添加,不可修改

List.of()

Set.of()

Map.of()

Map.ofEntries()

List<Integer> list1 = List.of(1, 2, 3, 4, 5);

Set<Integer> set1 = Set.of(234, 12, 310, 235, 21, 39, 91, 23);

//KVKV……

Map<String, Integer> map1 = Map.of("Tom", 12, "Jerry", 23, "Hanmeimei", 15);

//static <K, V> Entry<K, V> entry(K k, V v) Map.entry()方法生成Map.Entry实现类的对象

Map<String, Integer> map2 = Map.ofEntries(Map.entry("Tom", 15), Map.entry("Jack", 18));

 

InputStream的新方法:transferTo()

transferTo() 把输入流中的所有数据直接自动地复制到输出流中

注意:Reader也有这个方法

ClassLoader loader = this.getClass().getClassLoader();

try(InputStream is = loader.getResourceAsStream("hello.txt"); FileOutputStream fos = new FileOutputStream("src\\hello1.txt")) {

    is.transferTo(fos); // 把输入流中的所有数据直接自动地复制到输出流中

    System.out.println("复制完成");

} catch (IOException e) {

    e.printStackTrace();

}

 

增强的 Stream API

Java 9 中,Stream API 变得更好,Stream 接口中添加了 4 个新的方法:takeWhile, dropWhile, ofNullable,还有个 iterate 方法的新重载方法,可以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代。

takeWhile 用于从 Stream 中获取一部分数据,接收一个 Predicate 来进行选择。返回从开头开始的按照指定规则尽量多的元素

dropWhile 与 takeWhile 相反,把符合条件的舍去,返回从第一个不符合条件开始的剩余元素。

List<Integer> list = Arrays.asList(27,11,35,47,65,38,25,9,43);

list.stream().takeWhile( x -> x < 48).forEach(System.out::println); //27 11 35 47

list.stream().dropWhile( x -> x < 48).forEach(System.out::println); //65 38 25 9 43

of()  参数中的多个元素,可以包含null值,null也算1个,也可以被输出。of()参数不能存储单个null值。否则,报异常

ofNullable():形参变量是可以为null值的单个元素。但是null不算个数,并且不会被输出

iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next) 这个 iterate 方法的新重载方法,可以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代。

Stream.iterate(1,x -> x < 1000,x -> x * 2).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);

//是把Optional里面存的 元素本身 作为Stream里的数据,而不是把里面的List拆开了

//System.out.println(optional.stream().count()); //1

//optional.stream().forEach(x -> {

//    System.out.println(x); //[Tom, Jerry, Tim]

//    System.out.println(x.getClass()); //class java.util.ArrayList

//});

//遍历List,把List再用stream()方法生成流,加入到optional.stream()生成的流中

optional.stream().flatMap(x -> x.stream()).forEach(System.out::println); //Tom Jerry Tim

 

JEPJDK Enhancement Proposal特性加强提议)

 

Java10新特性

Local-Variable Type Inference 局部变量类型推断

适用于以下情况:

//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);

}

 

//泛型的类型推断中,右边的泛型是根据左边的泛型推断,可以省略。但是如果左边写成了var,就只能看右边的泛型了。如果右边没写,就是没指定泛型类型

var list = new ArrayList<String>();

 

在局部变量中使用时,如下情况不适用:

//1.局部变量不赋值,就不能实现类型推断。(声明和赋值分开写也不行)

var num;

num = 10;

//2.lambda表示式中,左边的函数式接口不能声明为var

Supplier<Double> sup = () -> Math.random();

//var sup1= () -> Math.random();

 

//3.方法引用中,左边的函数式接口不能声明为var

Consumer<String> con = System.out::println;

//var con1 = System.out::println;

 

//4.数组的静态初始化中,注意如下的情况也不可以

int[] arr = {1,2,3,4};

var arr1 = new int[]{1,2,3,4}; //可以

//var arr2 = {1,2,3,4};

 

不适用以下的结构中:

//情况1:没有初始化的局部变量声明

var s = null;

var num;

//情况2:方法的返回类型

public var method1(){

    return 0;

}

//情况3:方法的参数类型

public String method2(var num){

    return null;

}

//情况4:构造器的参数类型

public Java10Test(var num){

 

}

//情况5:属性

var num;

//情况6catch

try{

 

}catch(var e){

    e.printStackTrace();

}

 

工作原理:在处理 var时,编译器先是查看表达式右边部分,并根据右边变量值的类型进行推断,作为左边变量的类型,然后将该类型写入字节码当中

编译器负责推断出类型,并把结果写入字节码文件,就好像是开发人员自己敲入类型一样。

注意:

l var不是一个关键字

 

集合新增创建不可变集合的方法

copyOf(Xxx coll) AbstractImmutableList 类型的,如果是,就直接返回,如果不是,则调用 of 创建一个新的集合。

//示例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>();

list2.add("aaa");

var copy2 = List.copyOf(list2);

System.out.println(list2 == copy2); // false

 

//示例12代码基本一致,为什么一个为true,一个为false?

//结论:copyOf(Xxx coll):如果参数coll本身就是一个只读集合,则copyOf()返回值即为当前的coll

//如果参数coll不是一个只读集合,则copyOf()返回一个新的集合,这个集合是只读的。

 

Java 11 新特性

新增了一系列字符串处理方法

//isBlank():判断字符串是否为空白 \t\n\r也算空白

System.out.println("   \t \n \r  \n   \t  ".isBlank()); //true

//strip():去除首尾空白 trim()适用范围更广

System.out.println("---" + "   \t \n   \n   \t  ".strip() + "---"); //------

System.out.println("---" + "   \t \n   \n   \t  ".trim() + "---"); //------

//stripTrailing():去除尾部空格 包括\t\n\r

System.out.println("---" + "   \t \n   \nabc \r  \t  ".stripTrailing() + "---");

//stripLeading():去除首部空格 包括\t\n\r

System.out.println("---" + "   \t \n   \nabc \r  \t  ".stripLeading() + "---");

//repeat(int count):复制字符串

String str1 = "abc";

var str2 = str1.repeat(5);

System.out.println(str1); //abc

System.out.println(str2); //abcabcabcabcabc

//lines().count():行数统计 lines()是返回了Stream<String>

String str3 = "abc\nab\ncabcabca\nbc\n";

System.out.println(str3.lines().count()); //4

 

Optional 加强,新增方法

op.isPresent() 判断内部的value是否存在

op.isEmpty() 判断内部的value是否为空 JDK11

ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) value非空,执行参数1功能;如果value为空,执行参数2功能 JDK9

Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) value非空,返回对应的Optionalvalue为空,返回形参封装的Optional

Stream<T> stream() value非空,返回仅包含此valueStream;否则,返回一个空的Stream

orElseThrow() value非空,返回value;否则抛异常NoSuchElementException

Optional<Object> op = Optional.empty();

System.out.println(op.isPresent()); //判断内部的value是否存在 false

System.out.println(op.isEmpty()); //判断内部的value是否为空 true

 

op = Optional.of("abc");

//orElseThrow():value非空,返回value;否则抛异常NoSuchElementException

Object obj = op.orElseThrow();

System.out.println(obj); //abc

 

Optional<String> op1 = Optional.of("hello");

op = Optional.empty();

//or:value非空,返回对应的Optionalvalue为空,返回形参封装的Optional

Optional<Object> op2 = op.or(() -> op1);

System.out.println(op2); //Optional[hello]

 

局部变量类型推断升级

var上添加注解的语法格式,在jdk10中是不能实现的。在JDK11中加入了这样的语法。

//错误的形式: 用注解时,必须要有类型, 可以加上varjdk10中不行)

//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

HttpClient替换原有的HttpURLConnection

它将 替 代 仅 适 用 于 blocking 模式的 HttpURLConnectionHttpURLConnection是在HTTP 1.0的时代创建的,并使用了协议无关的方法),并提供WebSocket HTTP/2的支持

 

更简化的编译运行程序

在我们的认知里面,要运行一个 Java 源代码必须先编译,再运行,两步执行动作。而在未来的 Java 11 版本中,通过一个 java 命令就直接搞定了,如以下所示:

java Javastack.java

一个命令编译运行源代码的注意点:

Ø 执行源文件中的第一个类, 第一个类必须包含主方法

Ø 并且不可以使用其它源文件中的自定义类, 本文件中的自定义类是可以使用的。

 

ZGC

l ZGC, A Scalable Low-Latency Garbage Collector(Experimental)ZGC, 这应该是JDK11最为瞩目的特性, 没有之一。 但是后面带了Experimental,说明这还不建议用到生产环境。

l ZGC是一个并发, 基于region, 压缩型的垃圾收集器, 只有root扫描阶段会STW(stop the world), 因此GC停顿时间不会随着堆的增长和存活对象的增长而变长。

l 优势:

Ø GC暂停时间不会超过10ms

Ø 既能处理几百兆的小堆, 也能处理几个T的大堆(OMG)

Ø G1相比, 应用吞吐能力不会下降超过15%

Ø 为未来的GC功能和利用colord指针以及Load barriers优化奠定基础

Ø 初始只支持64位系统

l ZGC的设计目标是:支持TB级内存容量,暂停时间低(<10ms),对整个程序吞吐量的影响小于15%。 将来还可以扩展实现机制,以支持不少令人兴奋的功能,例如多层堆(即热对象置于DRAM和冷对象置于NVMe闪存),或压缩堆

 

其他新特性

l Unicode 10

l Deprecate the Pack200 Tools and API

l 新的Epsilon垃圾收集器

l 完全支持Linux容器(包括Docker

l 支持G1上的并行完全垃圾收集

l 最新的HTTPS安全协议TLS 1.3

l Java Flight Recorder

 

202131421:56:49 完结,结尾拉到上面。

 

结尾

 

使用 Microsoft OneNote 2016 创建。 版权所有:古木苏