一、接口的私有方法
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实例。新的List、Set、Map的静态工厂方法可以更方便地创建集合的不可变实例。
List接口,Set接口,Map接口:里边增加了一个静态的方法of,可以给集合一次性添加多个元素:
使用前提:当集合中存储的元素的个数已经确定了,不在改变时使用
List firsnamesList = List.of("Joe","Bob","Bill");
调用集合中静态方法of(), 可以将不同数量的参数传输到此工厂方法中。 此功能可用于Set和List, 也可用于Map的类似形式。 此时得到的集合, 是不可变的:在
创建后, 继续添加元素到这些集合会导致 “UnsupportedOperationException” 。
由于Java 8中接口方法的实现, 可以直接在List, Set和Map的接口内定义这些方法,便于调用。
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 代码。