Java9新特性

目录

一、Java9

1.JDK 和 JRE 目录结构的改变

2.模块化系统

3.Java的REPL工具: jShell命令

4.语法改进:接口的私有方法

5.语法改进:try语句

6.String字符串的变化

6.1、String存储结构变更

6.2、String声明时,不允许使用_来命名变量名

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

8.InputStream 加强

9.@Deprecated废弃注解追加since和forRemoval属性


自从 2017 年 9 月 21 日 Java 9 正式发布之时,Oracle 就宣布今后会按照 每六个月一次的节奏进行更新。

JDK官方下载地址

一、Java9

        Java的更新从传统的以特性驱动的发布周期,转变为以时间驱动的 (6 个月为周期)发布模式.

针对企业客户的需求,Oracle 将以三年为周期发布长期支持版本(long term support)。

1.JDK 和 JRE 目录结构的改变

 

2.模块化系统

        众所周知,Java 已经发展超过 20 年(95 年最初发布),Java 和相关生态在不断丰富的同时也越来越暴露出一些问题:

①Java 运行环境的膨胀和臃肿。每次JVM启动的时候,至少会有30~60MB的内存加载,主要原因是JVM需要加载rt.jar,不管其中的类是否被classloader加载,第 一步整个jar都会被JVM加载到内存当中去。

②当代码库越来越大,创建复杂。不同版本的类库交叉依赖导致让人头疼的问题,这些都阻碍了 Java 开发和运行效率的提升。

③很难真正地对代码进行封装, 而系统并没有对不同部分(也就是 JAR 文件)之间的依赖关系有个明确的概念。每一个公共类都可以被类路径之下任何其它的公共类所访问到,这样就会导致无意中使用了并不想被公开访问的 API。

        java9中将rt.jar分成了不同的模块,一个模块下可以包含多个包,模块之间存在着依赖关系,其中java.base模块是基础模块,不依赖其他模块。让jvm加载程序的必要模块,并非全部模块,达到了瘦身的效果。

        模块(module)的概念,其实就是package外再裹一层,不声明默认就是隐藏。因此,模块化使得代码组织上更安全,因为它可以指定哪些部分可以暴露,哪些部分隐藏。

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

        jar包中含有.class文件,配置文件。jmod除了包含这两个文件之外,还有native library,legal licenses等,两者主要的区别是jmod主要用在编译期和链接期,并非运行期,因此对于很多开发者来说,在运行期仍然需要使用jar包。

模块化的优点:

        1、精简jvm加载的class类,提升加载速度

        2、对包更精细的控制,提高安全

模块与包类似,只不过一个模块下可以包含多个包。

例:
项目-----公司
模块-----部门
包名-----小组
类-------员工

演示:

1、创建项目,项目下分别创建2个模块test9和demo1

2、在模块test9下

创建com.test.bean Cat

package com.test.bean;

public class Cat {
    public void eat(){
        System.out.println("吃鱼");
    }
}

创建com.test.bean1 Dog

package com.test.bean1;

public class Dog {
}

在src下创建module-info.java。

module test9 {//test9是本模块名
    exports com.test.bean;//导出包
    opens com.test.bean1;//导出包,只能通过反射的方式访问
}

3、在模块demo1下

创建com.demo Test

package com.demo;

import com.test.bean.Cat;

public class Test {
    public static void main(String[] args) throws Exception {
        Cat cat=new Cat();//访问不到Cat,需要配置module-info.java文件
        cat.eat();
        Class<?> clazz=Class.forName("com.test.bean1.Dog");
        Object obj = clazz.getDeclaredConstructor().newInstance();
    }
}

在src下创建module-info.java。

module demo1 {//demo1 是本模块名
    requires test9;//引入test9模块requires:指明对其它模块的依赖。
}

3.Java的REPL工具: jShell命令

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

Java 9 中终于拥有了 REPL工具:jShell

安装JDK9以上版本。

调出jShell:cmd中输入:jshell       回车   

C:\Users\Administrator>jshell
|  欢迎使用 JShell -- 版本 21.0.1
|  要大致了解该版本, 请键入: /help intro

jshell> System.out.println("Hello World!")
Hello World!

jshell> int a=10;
a ==> 10

jshell> int b=20;
b ==> 20

jshell> System.out.println(a+b)
30

jshell>

获得帮助:/help intro

导入指定的包:import java.util.*;

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

只需按下 Tab 键,就能自动补全代码

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

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

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

退出jShell:/exit

4.语法改进:接口的私有方法

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

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

public interface MyInterface {

    void eat();
    default void  fly(){
        sleep();
    }

    static  void run(){
        System.out.println("run");
    }

    private void sleep(){
        System.out.println("sleep");
    }

}

5.语法改进:try语句

        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();
}

6.String字符串的变化

6.1、String存储结构变更

        以前的版本中String内部使用了char数组存储,对于使用英文的人来说,一个字符用一个字节就能存储,使用char存储字符会浪费一半的空间,因此在jdk9中将String内部的char数组改成了byte数组加上编码标记,节约了一半的内存空间(纯英文节约一半内存空间)。

public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
    @Stable
    private final byte[] value;

    /**
     * The identifier of the encoding used to encode the bytes in
     * {@code value}. The supported values in this implementation are
     *
     * LATIN1
     * UTF16
     *
     * @implNote This field is trusted by the VM, and is a subject to
     * constant folding if String instance is constant. Overwriting this
     * field after construction will cause problems.
     */
    private final byte coder;
...
    static final boolean COMPACT_STRINGS;

    static {
        COMPACT_STRINGS = true;
    }

...
    @Native static final byte LATIN1 = 0;
    @Native static final byte UTF16  = 1;
}

String中增加了下面2个成员变量:

1、COMPACT_STRINGS:判断是否压缩,默认是true,若为false,则不压缩,使用UTF16编码

2、coder用来区分使用的字符编码,分别为LATIN1(值为0)和UTF16(值为1)

char c= 'a';//2个字节
byte b=97;//1个字节

byte数组如何存储中文呢?通过源码(StringUTF16类中的toBytes方法)得知,在使用中文字符串时,1个中文会被存储到byte数组中的两个元素上,即存储1个中文,byte数组长度为2,存储2个中文,byte数组长度为4.

例:

String str="好";

好,对应的Unicode码二进制为0101100101111101,分别取出高8位和低8位,放入byte数组中{01011001,01111101}这样就利用byte数组的2个元素保存了1个中文。

        当字符串中存储了中英混合的内容时,1个英文字符会占用2个byte的数组位置,例如下面代码底层byte数组的长度为8。

String str="好hao";

        在获取字符串长度时,若存储的内容存在中文,是不能直接获取byte数组的长度作为字符串长度的,String源码中有向右移动1位的操作(即除以2),这样才能获取正确的字符串长度。

打断点//F5

public class Test {
    public static void main(String[] args) {
        char[] name = {'好', '如'};
        String str = new String(name);//F5 先进入new String()//F5
        System.out.println(str);
    }
}

6.2、String声明时,不允许使用_来命名变量名

String _="";//java9之后不允许使用_来命名变量名

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

List<String> namesList = new ArrayList <>();
namesList.add("Joe");
namesList.add("Bob");
namesList.add("Bill");
namesList = Collections.unmodifiableList(namesList);
System.out.println(namesList);
//缺点:我们一下写了五行。即:它不能表达为单个表达式。

List firsnamesList = List.of(“Joe”,”Bob”,”Bill”);

        调用集合中静态方法of(),可以将不同数量的参数传输到此工厂方法中。此功能可用于Set和List,也可用于Map的类似形式。此时得到的集合,是不可变的:在创建后,继续添加元素到这些集合会导致 “UnsupportedOperationException” 。 由于Java 8中接口方法的实现,可以直接在List,Set和Map的接口内定义这些方法, 便于调用。

8.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();
}

9.@Deprecated废弃注解追加since和forRemoval属性

since:标识是从哪个版本被废弃了

forRemoval:=true :标识该废弃的内容会在未来的某个版本中移除

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
public @interface Deprecated {
    /**
     * Returns the version in which the annotated element became deprecated.
     * The version string is in the same format and namespace as the value of
     * the {@code @since} javadoc tag. The default value is the empty
     * string.
     *
     * @return the version string
     * @since 9
     */
    String since() default "";

    /**
     * Indicates whether the annotated element is subject to removal in a
     * future version. The default value is {@code false}.
     *
     * @return whether the element is subject to removal
     * @since 9
     */
    boolean forRemoval() default false;
}

例:since

public final class Class<T> implements java.io.Serializable,
                              GenericDeclaration,
                              Type,
                              AnnotatedElement,
                              TypeDescriptor.OfField<Class<?>>,
                              Constable {
....
    @CallerSensitive
    @Deprecated(since="9")
    public T newInstance()
        throws InstantiationException, IllegalAccessException
    {
...

例:forRemoval

public class Object {
...
    @Deprecated(since="9", forRemoval=true)
    protected void finalize() throws Throwable { }

Java10新特性

Java8新特性

一个程序员最重要的能力是:写出高质量的代码!!
有道无术,术尚可求也,有术无道,止于术。
无论你是年轻还是年长,所有程序员都需要记住:时刻努力学习新技术,否则就会被时代抛弃

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

杀神lwz

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

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

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

打赏作者

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

抵扣说明:

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

余额充值