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)。