JDK9新特性

传送门

SpringMVC的源码解析(精品)
Spring6的源码解析(精品)
SpringBoot3框架(精品)
MyBatis框架(精品)
MyBatis-Plus
SpringDataJPA
SpringCloudNetflix
SpringCloudAlibaba(精品)
Shiro
SpringSecurity
java的LOG日志框架
Activiti(敬请期待)
JDK8新特性
JDK9新特性
JDK10新特性
JDK11新特性
JDK12新特性
JDK13新特性
JDK14新特性
JDK15新特性
JDK16新特性
JDK17新特性
JDK18新特性
JDK19新特性
JDK20新特性
JDK21新特性
其他技术文章传送门入口

前言

JDK9提供了超过150项新功能特性,包括倍受期待的模块化系统,可交互的REPL工具:jshell,JDK编译工具,Java公共API和私有代码,以及安全增强、扩展提升、性能管理改善等。可以说Java9是一个庞大的系统工程,完全做了一个整体的改变。
具体来讲:
● JDK和JRE的改变
● 模块化系统
● JShell命令
● 多版本兼容jar包
● 接口的私有方法
● 砖石操作符的使用升级
● try语句
● 下划线使用限制
● String储存结构变更
● 便利的集合特性:of()
● 增强的Stream API
● 多分辨率图像API
● 全新的HTTP客户端API
● Deprecated的相关API
● 智能Java编译工具
● 统一的JVM日志系统
● javadoc的HTML5支持
● javascript引擎升级:Nashorn
● Java的动态编译器

一、JDK和JRE的改变

1、JDK8的目录结构

在这里插入图片描述

2、JDK9的目录结构

在这里插入图片描述
说明:
在这里插入图片描述
这个新特性只要了解下就可以了,这个目录结构是方便为了接下来新特性做保证。jdk8和jdk9的安装还是会额外安装一次jre。

二、模块化系统

1、产生背景

众所周知,Java 已经发展超过 20 年(95 年最初发布),Java 和相关生态在不断丰富的同时也越来越暴露出一些问题:
● Java 运行环境的膨胀和臃肿。每次 JVM 启动的时候,至少会有 30~60MB 的内存加载,主要原因是 JVM 需要加载 rt.jar,不管其中的类是否被classloader 加载,第一步 整个 jar 都会被 JVM 加载到内存当中去(而模块化可以根据模块的需要加载程序运行需要的 Class)
● 当代码库越来越大,创建复杂,盘根错节的「面条式代码」的几率呈指数级的增长。不同版本的 类库交叉依赖 导致让人头疼的问题,这些都 阻碍了 Java 开发和运行效率的提升
● 很难真正地对代码进行封装,而系统并没有对不同部分(也就是 JAR 文件)之间的依赖关系有个明确的概念。每一个公共类都可以被类路径之下任何其它的公共类所访问到,这样就会导致无意中使用了并不想被公开访问的 API
● 类路径本身也存在问题: 你怎么知晓所有需要的 JAR 都已经有了,或者是不是会有重复的项呢
● 同时,由于 兼容性等各方面的掣肘,对 Java 进行大刀阔斧的革新越来越困难,Jigsaw 从 Java 7 阶段就开始筹备,Java 8 阶段进行了大量工作,终于在 Java 9 里落地,一种千呼万唤始出来的意味。
● Jigsaw 项目(后期更名为 Modularity)的工作量和难度大大超出了初始规划。JSR 376 Java 平台模块化系统(JPMS,Java Platform Module System)作为 Jigsaw 项目的核心,其主体部分被分解成 6 个 JEP(JDK Enhancement Proposals)。
● 作为 Java 9 平台 最大的一个特性,随着 Java 平台模块化系统的落地,开发人员无需再为不断膨胀的 Java 平台苦恼,例如,您可以 使用 jlink 工具,根据需要定制运行时环境。这对于拥有大量镜像的容器应用场景或复杂依赖关系的大型应用等,都具有非常重要的意义。
● 本质上讲,模块(module)的概念,其实就是 package 外再裹一层,也就是说,用模块来管理各个 package,通过声明某个 package 暴露,不声明默认就是隐藏。因此,模块化使得代码组织上 更安全,因为它可以指定哪些部分可以暴露,哪些部分隐藏。

2、设计理念

模块独立、化繁为简。
模块化(以 Java 平台模块系统的形式)将 JDK 分成一组模块,可以在编译时,运行时或者构建时进行组合。

3、实现目标

● 主要目的在于减少内存的开销
● 只须必要模块,而非全部 JDK 模块,可 简化各种类库和大型应用的开发和维护
● 改进 Java SE 平台,使其可以 适应不同大小的计算设备
● 改进其安全性,可维护性,提高性能

4、使用案例

idea在jdk9安装环境下新建的springboot3Demo项目(jdk17环境也可以)
springboot3Demo中新建两个Module
● java9provider:该模块主要提供Person类
● java9consumer:该模块主要使用Person类
在这里插入图片描述
在这里插入图片描述
Person类代码:

package test.java9provider;



import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;

public class Person implements Serializable {


    private Integer age;
    private String name;

    public Person(Integer age, String name) {
        this.age = age;
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
        "age=" + age +
        ", name='" + name + '\'' +
        '}';
    }
}

java9consumer中使用Person类会发现如下截图问题,Person类在另一个模块中,无法直接使用。
在这里插入图片描述
jdk9有了新的方案,就是模块化系统。
分别如图在两个模块下的src文件夹右键new一个module-info.java文件出来。
在这里插入图片描述
在这里插入图片描述
java9provider模块中module-info.java文件代码:

module java9provider {
    // 导出相应的包(Person所在的包)
    exports test.java9provider;
}

java9consumer模块中module-info.java文件代码:

module java9consumer {
    // 需要的模块名称
    requires java9provider;
}

java9consumer模块中使用Person代码:

package test.java9consumer;


import test.java9provider.Person;

public class ModuleTest {
    public static void main(String[] args) {
        Person person = new Person(18,"张三");// 仍然需要点一下Add dependency on module
        System.out.println(person);
    }
}

测试结果如下图,可以正常使用Person类了,并且打印出Person信息:
在这里插入图片描述

三、JShell命令

1、产生背景

像 Python 和 Scala 之类的语言早就有交互式编程环境 REPL(read - evaluate - print - loop)了,以交互式的方式对语句和表达式进行求值。开发者只需要输入一些代码,就可以在编译前获得对程序的反馈。而 之前的 Java 版本要想执行代码,必须创建文件、声明类、提供测试方法方可实现。

2、设计理念

即写即得、快速运行

3、实现目标

Java 9 中终于拥有了 REPL 工具:JShell。利用 JShell 在没有创建类的情况下直接声明变量,计算表达式,执行语句。即开发时可以在命令行里直接运行 Java 的代码,而无需创建 Java 文件,无需跟人解释 public static void main(String[] args) 这句话。
● JShell 也可以从 文件中加载语句 或者将语句保存到文件中。
● JShell 也可以是 Tab 键进行自动补全 和 自动添加分号。

4、使用案例

进入jdk9安装目录bin下面找到jshell.exe双击运行(可以用jdk17代替测试)
在这里插入图片描述

4.1、简单变量使用

在这里插入图片描述

和在 Java 文件写代码一样,JShell 会自动执行输入的代码,检查代码语法,并且代码保存起来,当退出JShell后,再清空代码。
注意:在 JShell 环境下,语句末尾的 ; 是可选的。但推荐还是最好加上。提高代码可读性。

4.2、简单方法使用

在这里插入图片描述
上图既有方法定义,又有方法修改和方法使用。

4.3、导入指定的包

在这里插入图片描述
/imports 可以查看默认已经导入的包,import 包名 导入具体的包。

4.4、/的用法

/tab 可以查看其他功能
在这里插入图片描述
tab的功能和使用Linux系统的功能一样,可以补全单词等等。
/list 可以看到当前有效的代码
在这里插入图片描述
/vars 可以看到定义的变量
在这里插入图片描述
/methods 可以看到定义的方法
在这里插入图片描述
/edit add 可以单独弹出add方法的编辑框,编辑处理
在这里插入图片描述

4.5、从外部文件加载源代码

C盘事先编辑好的hello.java文件,里面就一句代码 System.out.println(“JShell very good”);
在这里插入图片描述
/open C:\hello.java 可以直接加载外部hello.java源代码
在这里插入图片描述

4.6、编译时异常隐藏

正常写代码的时候,有些代码会有异常提示,需要用try等处理异常
在这里插入图片描述
在这里插入图片描述
在jshell中则不用专门写try,因为在后台将异常代码隐藏了,实际上是有try等代码的效果的,/list也是看不到的。
在这里插入图片描述

4.7、退出JShell

/exit 可以直接退出JShell
在这里插入图片描述

四、多版本兼容jar包

当一个新版本的 Java 出现的时候,你的库用户要花费数年时间才会切换到这个新的版本。这就意味着 库得去向后兼容你想要支持的最老的 Java 版本(许多情况下就是 Java 6 或者 Java7) 。这实际上意味着未来的很长一段时间,你都不能在库中运用 Java 9 所提供的新特性。幸运的是,多版本兼容 jar 功能能让你创建仅在特定版本的 Java 环境中运行库程序选择使用的 Class 版本。

1、简单例子

比如一个第三方项目hello.jar,这个项目使用了java8类库中的一个类,假设这个类有打印输出,打印输出java8,在java9时,这个类更新了,打印输出java9。
当我们自己开发环境是jdk8的时候,引入这个第三方hello.jar包,打印输出就是java8。
当我们自己开发环境是jdk9的时候,引入这个第三方hello.jar包,打印输出就是java9。

2、本质原因

jdk9以后支持了多版本兼容jar包,其实就是打包出来的hello.jar包多了一些类文件,比如jdk类库中的类A,默认打包后,只有一个类A.class,但在多版本兼容方式jdk9版本打包后,就会有两个类A.class,一个类A是默认的,对应jdk8版本的,另一个类A是jdk9版本的。以此类推,如果是多版本兼容方式jdk10版本打包后,就会有三个类A,分别是jdk8版本的类A.calss、jdk9版本的类A.calss、jdk10版本的类A.calss,在不同开发环境下运行,功能可能不一样。

点击查看 9分钟案例视频 更容易理解

五、语法改进-接口的私有方法

Java 8 中规定接口中的方法除了抽象方法之外,还可以定义静态方法和默认的方法。一定程度上,扩展了接口的功能,此时的接口更像是一个抽象类。
在 Java 9 中,接口更加的灵活和强大,连方法的访问权限修饰符都可以声明为 private 的了,此时方法将不会成为你对外暴露的 API 的一部分。

接口语法:
jdk7:只能声明全局常量(public static final)和抽象方法(public abstract)

void method1();

jdk8:增加了静态方法和默认方法(可以有实体方法了,不全是抽象方法)

// 静态方法
public static void method2(){
    System.out.println("method2");
}
// 默认方法
default void method3(){
    System.out.println("method3");
}

jdk9:增加了私有方法(权限修饰符可以为private了,jdk9之前都是public,只是public可以省略不写)

private void method4();

六、语法改进-钻石操作符Diamond Operator使用升级

1、使用说明

List<String>中的<>这个符号就是砖石操作符,其实就是表示泛型的操作符。
package com.zt.jdk9NewFeatures;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Jdk9NewFeatures {

    private List<String> flattenStrings(List<String>... lists) {
        Set<String> set1 = new HashSet<>();// 编译不报错,类型推断
        Set<String> set2 = new HashSet<String>(){};// 编译不报错,这边其实是想写匿名内部类
        Set<String> set3 = new HashSet<>(){};// 编译报错,这边其实是想写匿名内部类,如果在jdk8不单独声明泛型中的类型,就会报错,而在jdk9中新增了这项功能
        for (List<String> list : lists) {
            set1.addAll(list);
        }
        return new ArrayList<>(set1);
    }
}

在这里插入图片描述
在jdk8上面代码在不声明泛型类型的时候,写匿名内部类会报错,而在jdk9中新增了特性,我们将能够与匿名实现类共同使用砖石操作符。

2、使用案例

package com.zt.jdk9NewFeatures;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Jdk9NewFeatures {

    private List<String> flattenStrings(List<String>... lists) {
        Set<String> set = new HashSet<>(){
            // 创建一个继承于HashSet的匿名子类对象
            // 可以覆写一些HashSet的方法
        };
        for (List<String> list : lists) {
            set.addAll(list);
        }
        return new ArrayList<>(set);
    }
}

七、语法改进-try语句

在jdk8中try语句可以自动关闭资源,在jdk9中对该功能进一步进行了加强。


public static void main(String[] args) {
    // jdk8版本写法
    InputStreamReader reader1 = null;
    try {
        reader1 = new InputStreamReader(System.in);
        reader1.read();// 读取数据
    } catch (IOException e) {
        throw new RuntimeException(e);
    } finally {
        // 资源关闭操作
        if (reader1 != null) {
            try {
                reader1.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
    // jdk8升级写法,要求资源对象的实例化必须放在try的一对()内完成,会主动关闭资源。
    try (InputStreamReader reader2 = new InputStreamReader(System.in); OutputStreamWriter writer2 = new OutputStreamWriter(System.out)) {
        reader2.read();// 读取数据
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    // jdk9中,可以在try()中调用已经实例化的资源对象,会主动关闭资源。
    InputStreamReader reader3 = new InputStreamReader(System.in);// 此时的reader3是个final的,因为try里面关闭的是它,不能再赋值修改了。
    OutputStreamWriter writer3 = new OutputStreamWriter(System.out);
    try (reader3; writer3) {
        reader3.read();// 读取数据
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

八、语法改进-下划线UnderScore使用的限制

在jdk8中,标识符可以独立使用“_”来命名:

// 在jdk8中,标识符可以独立使用“_”来命名
String _ = "hello";
System.out.println(_);

在jdk9中,“_”不再可以单独命名标识符了,如果使用会报错:

// 在jdk9中,“_”不再可以单独命名标识符了,如果使用会报错:
String _ = "hello";
System.out.println(_);

在这里插入图片描述

九、String存储结构变更

1、产生背景

String 类的jdk8实现将字符存储在字符数组cahr[]中,每个字符使用两个字节(16 位)。目前从许多不同的应用程序中收集的数据表明字符串是堆使用的主要组成部分,而且最重要的是对象仅包含拉丁字母 。这样的字符只需要一个字节的存储空间,因此只占内部字符数组空间的一半,许多这样的字符串对象将被闲置,空间被浪费。

jdk9建议更改 String 类的内部表示形式从 UTF-16 字符数组到字节数组再加上编码标志领域新的字符串类将存储编码为 ISO-8859-1 / 拉丁语-1(每个字符一个字节),或作为 UTF-16(两个字节每个字符),基于字符串的内容。编码标志将指示使用哪种编码。

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

jdk8的String部分代码截图:
在这里插入图片描述
jdk9的String部分代码截图:(实际用jdk17截图的)
在这里插入图片描述

2、拓展StringBuffer和StringBuilder

同样的,StringBuffer和StringBuilder也变化为了byte[]
String:不可变的字符序列,新的字符串会重新开辟内存空间;
StringBuffer:可变的字符序列,线程安全的,效率低;
StringBuilder:可变的字符序列,线程不安全的,效率高;

以上3个类在从cahr[]变为byte[]以后,开发者使用感受不到任何变化。

十、便利的集合特性:of()

1、产生背景

jdk8中要创建一个只读不可改变的集合,必须构造和分配它,然后添加元素,最后包装成一个不可修改的集合。
比如:

public static void main(String[] args) {
    // 创建一个只读特点的集合
    List<String> list = new ArrayList<>();
    list.add("张三");
    list.add("李四");
    // 调用Collections中的方法,将list变为只读的
    List<String> listNew = Collections.unmodifiableList(list);
    listNew.add("王五");// 只读的再去增加就会报异常  java.lang.UnsupportedOperationException
    listNew.forEach(System.out::println);

}

在这里插入图片描述
利用Collections中方法优化:

// 创建只读list
List<Integer> list = Collections.unmodifiableList(Arrays.asList(1, 2, 3));
// 创建只读set
Set<Integer> set = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(1, 2, 3)));
// 创建只读Map
Map<String, String> map = Collections.unmodifiableMap(new HashMap<String, String>() {
    {
        put("k1", "v1");
        put("k2", "v2");
    }
});

jdk9中引入了新方法,使得类似事情更容易表达。

2、使用案例

jdk9中给各个集合引入了 of() 静态方法,该方法代替 Collections.unmodifiableXXX 创建出 只读、不可改变 的集合。

    // jdk9中,创建一个只读特点的集合
    // 创建只读list
    List<Integer> list = List.of(1, 2, 3);
    // 创建只读set
    Set<Integer> set = Set.of(1, 2, 3);
    // 创建只读Map(方式一)
    Map<String, String> map1 = Map.of("k1", "v1", "k2", "v2");
    // 创建只读Map(方式二)
    Map<String, String> map2 = Map.ofEntries(Map.entry("k1", "v1"), Map.entry("k2", "v2"));

十一、增强的Stream API

1、产生背景

Java 的 Steam API 是 Java 标准库最好的改进之一,让开发者能够快速运算,从而能够有效的利用数据并行计算。jdk8 提供的 Steam 能够利用多核架构实现声明式的数据处理。

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

除了对 Stream 本身的扩展,Optional 和 Stream 之间的结合也得到了改进。现在可以通过 Optional 的新方法 stream() 将一个 Optional 对象转换为一个(可能是空的)Stream 对象。

2、使用案例

// jdk9新增 Stream API
// takeWhile()  用于从 Stream 中获取一部分数据,接收一个 Predicate 来进行选择。在有序的 Stream 中,takeWhile 返回从开头开始的尽量多的元素。
List<Integer> list = Arrays.asList(45, 49, 80, 110, 23, 54, 33);
list.stream().takeWhile(x -> x < 50).forEach(System.out::println);// 45  49
// 备注:到80的时候就不满足了,不管后面的元素是否满足,都不会取了,和filter过滤是不一样的。
list.stream().filter(x -> x < 50).forEach(System.out::println);// 45  49  23  33

// dropWhile()  行为与 takeWhile 相反,返回剩余的元素。
list.stream().dropWhile(x -> x < 50).forEach(System.out::println);// 80  110  23  54  33

// ofNullable()  jdk8 中 Stream 不能完全为 null,否则会报空指针异常。而 jdk9 中的 ofNullable 方法允许我们创建一个单元素 Stream,可以包含一个非空元素,也可以创建一个空 Stream。
Stream<Integer> stream1 = Stream.of(1, 2, 3, null);// jdk8中多个元素中可以有一个是null编译不会报错
System.out.println(stream1.count());// 4

//Stream<Integer> stream2 = Stream.of(null);// jdk8中单元素为null编译报错,报空指针异常
//System.out.println(stream2.count());// 上面一句就报错了

Stream<Integer> stream3 = Stream.ofNullable(1);// jdk9中新增的ofNullable方法,只能创建一个单元素的Stream
System.out.println(stream3.count());// 1

Stream<Integer> stream4 = Stream.ofNullable(null);// jdk9中新增的ofNullable方法可以存放为null单元素
System.out.println(stream4.count());// 0

// iterator()重载方法
// jdk8的时候iterator()方法
//Stream.iterate(0, x -> x + 1).forEach(System.out::println);// 从0开始,一直往下执行,所以一般要和limit配合限制一下
Stream.iterate(0, x -> x + 1).limit(2).forEach(System.out::println);// 0  1
// jdk9新增了iterator()重载方法,增加了一个判断条件参数,就不用用limit来限制了
Stream.iterate(0, x -> x < 2, x -> x + 1).forEach(System.out::println);// 0  1

// Optional 类中 新增了stream() 的使用
List<Integer> list2 = Arrays.asList(1, 2, 3);
Optional<List<Integer>> optional = Optional.ofNullable(list2);
Stream<List<Integer>> stream21 = optional.stream();// 注意流的元素是List<Integer> , 不是Integer,所以元素数量只有一个 [1, 2, 3]
stream21.forEach(System.out::println);// [1, 2, 3]
Stream<Integer> stream22 = optional.stream().flatMap(x -> x.stream());
stream22.forEach(System.out::println);// 1  2  3

十二、多分辨率图像API

1、产生背景

在 Mac 上,JDK 已经支持视网膜显示,但在 Linux 和 Windows 上,它并没有。在那里,Java 程序在当前的高分辨率屏幕上可能看起来很小,不能使用它们。这是因为像素用于这些系统的大小计算(无论像素实际有多大)。毕竟,高分辨率显示器的有效部分是像素非常小。

JEP 263 以这样的方式扩展了 JDK,即 Windows 和 Linux 也考虑到像素的大小。为此,使用比现在更多的现代 API:Direct2D for Windows 和 GTK +,而不是 Xlib for Linux 图形,窗口和文本由此自动缩放。

JEP 251 还提供处理多分辨率图像的能力,即 包含不同分辨率的相同图像的文件。根据相应屏幕的 DPI 度量,然后以适当的分辨率使用图像。

2、使用说明

● 新的 API 定义在 java.awt.image 包下
● 将不同分辨率的图像封装到一张(多分辨率的)图像中,作为它的变体
● 获取这个图像的所有变体
● 获取特定分辨率的图像变体,表示一张已知分辨率单位为 DPI 的特定尺寸大小的逻辑图像,并且这张图像是最佳的变体
● 基于当前屏幕分辨率大小和运用的图像转换算法,java.awt.Graphics 类可以从接口 MultiResolutionImage 获取所需的变体
● MultiResolutionImage 的基础实现是 java.awt.image.BaseMultiResolutionImage。

十三、全新的HTTP客户端API

1、产生背景

HTTP,用于传输网页的协议,早在 1997 年就被采用在目前的 1.1 版本中。直到 2015 年,HTTP2 才成为标准。
在这里插入图片描述
HTTP/1.1 和 HTTP/2 的主要区别是如何在客户端和服务器之间构建和传输数据。HTTP/1.1 依赖于请求/响应周期。HTTP/2 允许服务器 push 数据:它可以发送比客户端请求更多的数据。这使得它可以优先处理并发送对于首先加载网页至关重要的数据。

jdk9 中有新的方式来处理 HTTP 调用。它提供了一个新的 HTTP 客户端(HttpClient),它将 替代仅适用于 blocking 模式的 HttpURLConnection(HttpURLConnection 是在 HTTP 1.0 的时代创建的,并使用了协议无关的方法),并提供 对 WebSocket 和 HTTP/2 的支持。

此外,HTTP 客户端还提供 API 来处理 HTTP/2 的特性,比如流和服务器推送等功能。

全新的 HTTP 客户端 API 可以从 jdk.incubator.httpclient 模块中获取。因为在默认情况下,这个模块是不能根据 classpath 获取的,需要使用 add modules 命令选项配置这个模块,将这个模块添加到 classpath 中。

2、使用案例

package com.zt.jdk9NewFeatures;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.*;
import java.util.stream.Stream;

public class Jdk9NewFeatures {

    public static void main(String[] args) {
        // jdk9 中 使用 HttpClient 替换原有的 HttpURLConnection
        try {
            HttpClient client = HttpClient.newHttpClient();
            HttpRequest req = HttpRequest.newBuilder(URI.create("https://www.baidu.com")).GET().build();
            HttpResponse<String> response = null;
            response = client.send(req, HttpResponse.BodyHandlers.ofString());
            System.out.println(response.statusCode());// 200
            System.out.println(response.version().name());// HTTP_1_1
            System.out.println(response.body());// 内容太长,看打印输出
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}    

打印输出:

200
HTTP_1_1
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus=autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn" autofocus></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=https://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');
                </script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>使用百度前必读</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a>&nbsp;京ICP证030173号&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>

十四、Deprecated的相关API

jdk9 废弃或者移除了几个不常用的功能。其中最主要的是 Applet API,现在是标记为废弃的。随着对安全要求的提高,主流浏览器已经取消对 Java 浏览器插件的支持。HTML5 的出现也进一步加速了它的消亡。开发者现在可以使用像 Java Web Start 这样的技术来代替 Applet,它可以实现从浏览器启动应用程序或者安装应用程序。

同时,appletviewer 工具也被标记为废弃

十五、智能Java编译工具

智能 java 编译工具(sjavac) 的第一个阶段始于 JEP139 这个项目,用于 在多核处理器情况下提升 JDK 的编译速度。如今,这个项目已经进入第二阶段,即 JEP199,其目的是改进 Java 编译工具,并 取代目前 JDK 编译工具 javac,继而成为 Java 环境默认的通用的智能编译工具。

jdk9 还 更新了 javac 编译器 以便能够将 jdk9 代码编译运行在低版本 Java 中。

十六、统一的JVM日志系统

日志是解决问题的唯一有效途径:曾经很难知道导致 JVM 性能问题和导致 JVM 崩溃的根本原因。不同的 JVM 日志的碎片化和日志选项(例如:JVM 组件对于日志使用的是不同的机制和规则),这使得 JVM 难以进行调试。

解决该问题最佳方法:对所有的 JVM 组件引入一个单一的系统,这些 JVM 组件支持细粒度的和易配置的 JVM 日志。

jdk9 已经将 G1 作为默认的垃圾回收器,统一处理新生代和老年代的垃圾回收。

十七、javadoc的HTML5支持

jdk8:生成的 Java 帮助文档是在 HTML 4 中,而 HTML 4 已经是很久的标准了。

jdk9:javadoc 的输出,现在符合兼容 HTML 5 标准。

下图是 jdk8 中生成的 HTML 页面,如果想要找到一些类文档,必须在 Google 中搜索。
https://docs.oracle.com/javase/8/docs/api/
在这里插入图片描述
下图是在 jdk9中,添加了一个搜索框(右上角)
https://docs.oracle.com/javase/9/docs/api/overview-summary.html
在这里插入图片描述

十八、javascript引擎升级:Nashorn

Nashorn 项目在 jdk9 中得到改进,它为 Java 提供轻量级的 Javascript 运行时。Nashorn 项目跟随 Netscape 的 Rhino 项目,目的是为了在 Java 中实现一个高性能但轻量级的 JavaScript 运行时。Nashorn 项目使得 Java 应用能够嵌入 JavaScript。它在 jdk8 中为 Java 提供一个 JavaScript 引擎。

jdk9 包含一个用来解析 Nashorn 的 ECMAScript 语法树的 API。这个 API 使得 IDE 和服务端框架不需要依赖 Nashorn 项目的内部实现类,就能够分析 ECMAScript 代码。

十九、Java的动态编译器

1、产生背景

Oracle 一直在努力提高 Java 启动和运行时性能,希望其能够在更广泛的场景达到或接近本地语言的性能。但是,直到今天,谈到 Java,很多 C/C++ 开发者还是会不屑地评价为 启动慢,吃内存。

简单说,这主要是因为 Java 编译产生的类文件是 Java 虚拟机可以理解的二进制代码,而不是真正的可执行的本地代码,需要 Java 虚拟机 进行解释和编译,这带来了额外的开销。

2、使用说明

JIT(Just-in-time)编译器可以在运行时将热点编译成本地代码,速度很快。但是 Java 项目现在变得很大很复杂,因此 JIT 编译器需要 花费较长时间才能热身完,而且有些 Java 方法还没法编译,性能方面也会下降。AOT 编译就是为了解决这些问题而生的。

在 JDK 9 中,AOT(JEP 295:Ahead-of-Time Compilation)作为实验特性被引入进来,开发者可以利用新的 jaotc 工具将重点代码转换成类似类库一样的文件。虽然仍处于试验阶段,但这个功能使得 Java 应用在被虚拟机启动之前能够先将 Java 类编译为原生代码。此功能旨在改进小型和大型应用程序的启动时间,同时对峰值性能的影响很小。

但是 Java 技术供应商 Excelsior 的营销总监 Dmitry Leskov 担心 AOT 编译技术不够成熟,希望 Oracle 能够 等到 Java 10 时有个更稳定版本才发布。

另外 JVMCI(JEP 243:Java-Level JVM Compiler Interface)等特性,对于整个编程语言的发展,可能都具有非常重要的意义,虽然未必引起了广泛关注。目前 Graal Core API 已经被集成进入 Java 9,虽然还只是初始一小步,但是完全用 Java 语言来实现的可靠的、高性能的动态编译器,似乎不再是遥不可及,这是 Java 虚拟机开发工程师的福音。

与此同时,随着 Truffle 框架和 Substrate VM 的发展,已经让个别信心满满的工程师高呼 One VM to Rule Them All!, 也许就在不远的将来 Ploygot 以一种另类的方式成为现实。

二十、JDK9总结

1、在java9中看不到什么

1.1、一个标准化和轻量级的 JSON API

一个标准化和轻量级的 JSON API 被许多 Java 开发人员所青睐。但是由于资金问题无法在 Java 9 中见到,但并不会削减掉。Java 平台首席架构师 Mark Reinhold 在 JDK 9 邮件列中说:「这个 JEP 将是平台上的一个有用的补充,但是在计划中,它并不像 Oracle 资助的其他功能那么重要,可能会重新考虑 JDK 10 或更高版本中实现。」

1.2、新的货币 API

对许多应用而言货币价值都是一个关键的特性,但 JDK 对此却几乎没有任何支持。严格来讲,现有的 java.util.Currency 类只是代表了当前 ISO 4217 货币的一个数据结构,但 并没有关联的值或者自定义货币。JDK 对货币的运算及转换也没有内建的支持,更别说有一个能够代表货币值的标准类型了。

此前,Oracle 公布的 JSR 354 定义了一套新的 Java 货币 API:JavaMoney,计划会在 Java 9 中正式引入。但是目前没有出现在 JDK 9 中。

不过,如果你用的是 Maven 的话,可以做如下的添加,即可使用相关的 API 处理货币:

<dependency>
    <groupId>org.javamoney</groupId>
    <artifactId>moneta</artifactId>
    <version>0.9</version>
</dependency>

代码参考,可以访问 https://github.com/JavaMoney,里面已经给出了使用说明和示例。

2、展望

随着云计算和 AI 等技术浪潮,当前的计算模式和场景正在发生翻天覆地的变化,不仅对 Java 的发展速度提出了更高要求,也深刻影响着 Java 技术的发展方向。传统的大型企业或互联网应用,正在被云端、容器化应用、模块化的微服务甚至是函数(FaaS,Function-as-a-Service)所替代。

Java 虽然标榜面向对象编程,却毫不顾忌的 加入面向接口编程思想,又扯出 匿名对象 之概念,每增加一个新的东西,对 Java 的根本所在的面向对象思想的一次冲击。反观 Python,抓住面向对象的本质,又能在函数编程思想方面游刃有余。Java 对标 C/C++,以抛掉内存管理为卖点,却又陷入了 JVM 优化的噩梦。选择比努力更重要,选择 Java 的人更需要对它有更清晰的认识。

Java 需要在新的计算场景下,改进开发效率。这话说的有点笼统,我谈一些自己的体会,Java 代码虽然进行了一些类型推断等改进,更易用的集合 API 等,但仍然给开发者留下了过于刻板、形式主义的印象,这是一个长期的改进方向。(来自尚硅谷-宋红康)

  • 13
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝影铁哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值