Java9 新特性 (二)语法改进

一、接口的私有方法

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

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

  案例:

  MyInterface:

 1 public interface MyInterface {
 2     //如下的三个方法的权限修饰符都是public
 3     void methodAbstract();
 4 
 5     static void methodStatic(){
 6         System.out.println("我是接口中的静态方法");
 7     }
 8 
 9     default void methodDefault(){
10         System.out.println("我是接口中的默认方法");
11 
12         methodPrivate();
13     }
14     //jdk 9中允许接口中定义私有的方法
15     private void methodPrivate(){
16         System.out.println("我是接口中的私有方法");
17     }
18 }

  MyInterfaceImple:

 1 public class MyInterfaceImpl implements MyInterface {
 2 
 3 
 4     @Override
 5     public void methodAbstract() {
 6 
 7     }
 8 
 9     //@Override
10     public void methodDefault() {
11         System.out.println("实现类重写了接口中的默认方法");
12     }
13 
14     public static void main(String[] args) {
15         //接口中的静态方法只能由接口自己调用
16         MyInterface.methodStatic();
17         //接口的实现类不能调用接口的静态方法
18         //MyInterfaceImpl.methodStatic();
19 
20         MyInterfaceImpl impl = new MyInterfaceImpl();
21         impl.methodDefault();
22         //接口的私有方法,不能在接口外部调用
23         //impl.methodPrivate();
24     }
25 }

 

二、钻石操作符使用升级

    我们将能够与匿名实现类共同使用钻石操作符diamond operator) 在Java 8 中如下的操作是会报错的:
    

    编译报错信息: Cannot use “<>” with anonymous inner classes.

    Java 9中如下操作可以正常执行通过:

 1     //java9特性五:钻石操作符的升级
 2     @Test
 3     public void test2() {
 4         //钻石操作符与匿名内部类在java 8中不能共存。在java9可以。
 5         Comparator<Object> com = new Comparator<>() {
 6             @Override
 7             public int compare(Object o1, Object o2) {
 8                 return 0;
 9             }
10         };
11 
12         //jdk7中的新特性:类型推断
13         ArrayList<String> list = new ArrayList<>();
14     }

三、try语句

    Java 8 中, 可以实现资源的自动关闭, 但是要求执行后必须关闭的所有资源必须在try子句中初始化, 否则编译不通过。 如下例所示:

    Java8 之前:

 1         //java 8之前的资源关闭的操作
 2         InputStreamReader reader = null;
 3         try {
 4             reader = new InputStreamReader(System.in);
 5             char[] cbuf = new char[20];
 6             int len;
 7             if((len = reader.read(cbuf) )!= -1){
 8                 String str = new String(cbuf,0,len);
 9                 System.out.println(str);
10             }
11         } catch (IOException e) {
12             e.printStackTrace();
13         } finally {
14             if(reader != null){
15                 try {
16                     reader.close();
17                 } catch (IOException e) {
18                     e.printStackTrace();
19                 }
20 
21             }
22         }

    Java8 中:

 1         //java 8中资源关闭操作: Java 8 中,可以实现资源的自动关闭
 2         //要求自动关闭的资源的实例化必须放在try的一对小括号中
 3         try(InputStreamReader reader = new InputStreamReader(System.in)){
 4             char[] cbuf = new char[20];
 5             int len;
 6             if((len = reader.read(cbuf) )!= -1){
 7                 String str = new String(cbuf,0,len);
 8                 System.out.println(str);
 9             }
10         } catch (IOException e) {
11             e.printStackTrace();
12         }

  

    Java 9 中, 用资源语句编写try将更容易, 我们可以在try子句中使用已经初始化过的资源, 此时的资源是final

 1      //java9中资源关闭操作:需要自动关闭的资源的实例化可以放在try的一对小括号外。
 2        //此时的资源属性是常量,声明为final的,不可修改,具体读写操作省略
 3         InputStreamReader reader = new InputStreamReader(System.in);
 4        OutputStreamWriter writer = new OutputStreamWriter(System.out);
 5         try (reader, writer) {
 6 
 7             char[] cbuf = new char[20];
 8             int len;
 9             if((len = reader.read(cbuf) )!= -1){
10                 String str = new String(cbuf,0,len);
11                 System.out.println(str);
12             }
13 
14             //reader = null;
15         } catch (IOException e) {
16             e.printStackTrace();
17         }

四、String存储结构变更

    

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

    

    StringBuffer StringBuilder 是否仍无动于衷呢?

    

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

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

 1     //java8中的写法:
 2     @Test
 3     public void test1() {
 4         List<String> namesList = new ArrayList<>();
 5         namesList.add("Joe");
 6         namesList.add("Bob");
 7         namesList.add("Bill");
 8         //返回的namesList是一个只读的集合
 9         namesList = Collections.unmodifiableList(namesList);
10         namesList.add("Tom");
11         System.out.println(namesList);
12     }

  缺点:写下了多行,即不能表达单个表达式。

 1     @Test
 2     public void test2() {
 3         List<String> list = Collections.unmodifiableList(Arrays.asList("a", "b", "c"));
 4         Set<String> set = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("a", "b", "c")));
 5         // 如下操作不适用于jdk 8 及之前版本,适用于jdk 9
 6         Map<String, Integer> map = Collections.unmodifiableMap(new HashMap<>() {
 7             {
 8                 put("a", 1);
 9                 put("b", 2);
10                 put("c", 3);
11             }
12         });
13         map.forEach((k, v) -> System.out.println(k + ":" + v));
14     }

  调用 Arrays 的 asList() 方法也可以获取一个只读集合:

1     @Test
2     public void test3() {
3         //此时得到的集合list也是一个只读集合。
4         List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
5         //报异常
6         list.add(6);
7     }

  Java 9因此引入了方便的方法, 这使得类似的事情更容易表达。

  Java 9,添加了几种集合工厂方法,更方便创建少量元素的集合、map实例。新的ListSetMap的静态工厂方法可以更方便地创建集合的不可变实例。

  List接口,Set接口,Map接口:里边增加了一个静态的方法of,可以给集合一次性添加多个元素:

  使用前提:当集合中存储的元素的个数已经确定了,不在改变时使用

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

  

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

  

  Java9 新增方法:

 1     //java9新特性八:集合工厂方法:创建只读集合
 2     @Test
 3     public void test4() {
 4         List<Integer> list1 = List.of(1, 2, 3, 4, 5);
 5         //不能添加
 6         //list1.add(6);
 7         System.out.println(list1);
 8 
 9         Set<Integer> set1 = Set.of(23, 3, 54, 65, 43, 76, 87, 34, 46);
10         //不能添加
11         //set1.add(4);
12         System.out.println(set1);
13 
14         Map<String, Integer> map1 = Map.of("Tom", 23, "Jerry", 54, "HanMeimei", 12);
15         //不能添加
16         //map1.put("Lilei",34);
17 
18         System.out.println(map1);
19 
20         Map<String, Integer> map2 = Map.ofEntries(Map.entry("Tom", 34), Map.entry("Jerry", 21));
21         //map2.put("Lilei",34);
22         System.out.println(map2);
23     }

  Demo2:

 1  public static void main(String[] args) {
 2         List<String> list = List.of("a", "b", "a", "c", "d");
 3         System.out.println(list);//[a, b, a, c, d]
 4         //list.add("w");//UnsupportedOperationException:不支持操作异常
 5 
 6         //Set<String> set = Set.of("a", "b", "a", "c", "d");//IllegalArgumentException:非法参数异常,有重复的元素
 7         Set<String> set = Set.of("a", "b", "c", "d");
 8         System.out.println(set);
 9         //set.add("w");//UnsupportedOperationException:不支持操作异常
10 
11         //Map<String, Integer> map = Map.of("张三", 18, "李四", 19, "王五", 20,"张三",19);////IllegalArgumentException:非法参数异常,有重复的元素
12         Map<String, Integer> map = Map.of("张三", 18, "李四", 19, "王五", 20);
13         System.out.println(map);//{王五=20, 李四=19, 张三=18}
14         //map.put("赵四",30);//UnsupportedOperationException:不支持操作异常
15     }

  注意:  

    1. of方法只适用于 List接口,Set接口,Map接口,不适用于接接口的实现类;

    2. of方法的返回值是一个不能改变的集合,集合不能再使用add,put方法添加元素,会抛出异常;

    3. Set 接口和 Map 接口在调用 of 方法的时候,不能有重复的元素,否则会抛出异常;

六、InputStream 加强

  InputStream 终于有了一个非常有用的方法: transferTo,可以用来将数据直接传输到 OutputStream,这是在处理原始数据流时非常常见的一种用法,如下示例。

 1     //java9新特性九:InputStream的新方法:tranferTo()
 2     @Test
 3     public void test5() {
 4         ClassLoader cl = this.getClass().getClassLoader();
 5         try (InputStream is = cl.getResourceAsStream("hello.txt");
 6              OutputStream os = new FileOutputStream("src\hello1.txt")) {
 7             is.transferTo(os); // 把输入流中的所有数据直接自动地复制到输出流中
 8         } catch (IOException e) {
 9             e.printStackTrace();
10         }
11     }

七、增强的 Stream API

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

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

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

  1、takeWhile() 的使用

    用于从 Stream 中获取一部分数据, 接收一个 Predicate 来进行选择。 在有序的Stream 中, takeWhile 返回从开头开始的尽量多的元素

1     //takeWhile 返回从开头开始的按照指定规则尽量多的元素
2     @Test
3     public void test() {
4         List<Integer> list = Arrays.asList(45, 43, 76, 87, 42, 77, 90, 73, 67, 88);
5         list.stream().takeWhile(x -> x < 50).forEach(System.out::println); //45,43
6         System.out.println();
7         list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
8         list.stream().takeWhile(x -> x < 5).forEach(System.out::println); //1,2,3,4
9     }

  2、dropWhile() 的使用

    dropWhile 的行为与 takeWhile 相反, 返回剩余的元素

1      //dropWhile():与 takeWhile 相反,返回剩余的元素。
2     @Test
3     public void test() {
4         List<Integer> list = Arrays.asList(45, 43, 76, 87, 42, 77, 90, 73, 67, 88);
5         list.stream().dropWhile(x -> x < 50).forEach(System.out::println); //76,87,42,77,90,73,67,88
6         System.out.println();
7         list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
8         list.stream().dropWhile(x -> x < 5).forEach(System.out::println); //5,6,7,8
9     }

  3、ofNullable() 的使用

    Java 8 Stream 不能完全为null, 否则会报空指针异常。 而 Java 9 中的 ofNullable 方法允许我们创建一个单元素 Stream, 可以包含一个非空元素, 也可以创建一个空Stream

 1     @Test
 2     public void test1(){
 3         // of()参数不能存储单个null值。否则,报异常,报NullPointerException
 4          Stream<Object> stream1 = Stream.of(null);
 5          System.out.println(stream1.count());
 6 
 7 
 8         // of()参数中的多个元素,可以包含null值,不报异常,允许通过,
 9         Stream<String> stringStream = Stream.of("AA", "BB", null);
10         System.out.println(stringStream.count());// 3
11 
12 
13         // 不报异常,允许通过
14         List<String> list = new ArrayList<>();
15         list.add("AA");
16         list.add(null);
17         System.out.println(list.stream().count());// 2
18 
19 
20         // ofNullable():允许值为null,ofNullable():形参变量是可以为null值的单个元素
21         Stream<Object> stream2 = Stream.ofNullable(null);
22         System.out.println(stream2.count());// 0
23         Stream<String> stream = Stream.ofNullable("hello world");
24         System.out.println(stream.count());// 1
25     }

  4、iterate() 重载的使用

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

1     @Test
2     public void test3(){
3         //原来的控制终止方式
4         Stream.iterate(0,x -> x + 1).limit(10).forEach(System.out::println);
5 
6 
7         //java9中新增的重载的方法
8         Stream.iterate(0,x -> x < 100,x -> x + 1).forEach(System.out::println);
9     }

八、Optional 获取 Stream 的方法

  Optional 类提供了 Stream() 的使用:

 1     //java9新特性十一:Optional提供了新的方法stream()
 2     @Test
 3     public void test4(){
 4         List<String> list = new ArrayList<>();
 5         list.add("Tom");
 6         list.add("Jerry");
 7         list.add("Tim");
 8 
 9         Optional<List<String>> optional = Optional.ofNullable(list);
10         Stream<List<String>> stream = optional.stream();
11         //long count = stream.count();
12         //System.out.println(count);
13         stream.flatMap(x -> x.stream()).forEach(System.out::println);
14 
15     }

九、JavaScript 引擎升级:Nashorn

  Nashorn 项目在 JDK 9 得到改进, 它为 Java 提供轻量级的 Javascript 运行时Nashorn 项目跟随 Netscape Rhino 项目, 目的是为了在 Java 中实现一个高性能但轻量级的 Javascript 运行时。 Nashorn 项目使得 Java 应用能够嵌入Javascript。 它在 JDK 8 中为 Java 提供一个 Javascript 引擎。
  JDK 9 包含一个用来解析 Nashorn ECMAScript 语法树的 API这个 API 使得IDE 和服务端框架不需要依赖 Nashorn 项目的内部实现类, 就能够分析ECMAScript 代码。

  

 

原文地址:https://www.cnblogs.com/niujifei/p/15072786.html