赞
踩
Java 9 提供了超过150项新功能特性,包括备受期待的模块化系统、可交互的 REPL 工具:jshell,JDK 编译工具,Java 公共 API 和私有代码,以及安全增强、扩展提升、性能管理改善等。可以说Java 9是一个庞大的系统工程,完全做了一个整体改变。
一些重要的新特性如下:

模块化系统
谈到 Java 9 大家往往第一个想到的就是 Jigsaw 项目。众所周知,Java 已经
发展超过 20 年(95 年最初发布),Java 和相关生态在不断丰富的同时也越
来越暴露出一些问题:
本质上讲也就是说,用模块来管理各个package,通过声明某个package暴露,,模块(module)的概念,其实就是package外再裹一层,不声明默认就是隐藏。因此,模块化使得代码组织上更安全,因为它可以指定哪些部分可以暴露,哪些部分隐藏。
模块化系统的使用

要想在java9demo模块中调用java9test模块下包中的结构,需要在java9test的module-info.java中声明:
module java9test {
//package we export
exports com.atguigui.bean;
}
对应在java 9demo 模块的src 下创建module-info.java文件:
module java9demo {
requires java9test;
}
jShell命令
像Python 和 Scala 之类的语言早就有交互式编程环境 REPL (read - evaluate - print -loop)了,以交互式的方式对语句和表达式进行求值。开发者只需要输入一些代码,就可以在编译前获得对程序的反馈。而之前的Java版本要想执行代码,必须创建文件、声明类、提供测试方法方可实现。
Java 9 中终于拥有了 REPL工具:jShell。让Java可以像脚本语言一样运行,从
控制台启动jShell,利用jShell在没有创建类的情况下直接声明变量,计算表达式,执行语句。即开发时可以在命令行里直接运行Java的代码,而无需创建Java文件,无需跟人解释”public static void main(String[] args)”这句废话。
栗子:

语法改进:接口的私有方法
Java 8中规定接口中的方法除了抽象方法之外,还可以定义静态方法
和默认的方法。一定程度上,扩展了接口的功能,此时的接口更像是
一个抽象类。
在Java 9中,接口更加的灵活和强大,连方法的访问权限修饰符都可
以声明为private的了,此时方法将不会成为你对外暴露的API的一部分。
interface MyInterface { void normalInterfaceMethod(); default void methodDefault1() { init(); } public default void methodDefault2() { init(); } // This method is not part of the public API exposed by MyInterface private void init() { System.out.println("默认方法中的通用操作"); } } class MyInterfaceImpl implements MyInterface { @Override public void normalInterfaceMethod() { System.out.println("实现接口的方法"); } } public class MyInterfaceTest { public static void main(String[] args) { MyInterfaceImpl impl = new MyInterfaceImpl(); impl.methodDefault1(); // impl.init();//不能调用 } }
语法改进:钻石操作符使用升级
我们将能够与匿名实现类共同使用钻石操作符(diamond operator)在Java 8
中如下的操作是会报错的:
Comparator<Object> com = new Comparator<>(){
@Override
public int compare(Object o1, Object o2) {
return 0;
}
};
编译报错信息:Cannot use “<>” with anonymous inner classes.
Java 9中如下操作可以正常执行通过:
// anonymous classes can now use type inference
Comparator<Object> com = new Comparator<>(){
@Override
public int compare(Object o1, Object o2) {
return 0;
}
};
语法改进: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();
}
String存储结构变更
String 再也不用 char[] 来存储啦,改成了 byte[] 加上编码标记,节约
了一些空间。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
@Stable
private final byte[] value;
}
并且StringBuffer和StringBuilder也跟着变化。
集合工厂方法:快速创建只读集合
java创建可读集合的方法:

List firsnamesList = List.of(“Joe”,”Bob”,”Bill”);
调用集合中静态方法of(),可以将不同数量的参数传输到此工厂方法中。此功能
可用于Set和List,也可用于Map的类似形式。此时得到的集合,是不可变的:在
创建后,继续添加元素到这些集合会导致 “UnsupportedOperationException” 。
由于Java 8中接口方法的实现,可以直接在List,Set和Map的接口内定义这些方法,便于调用。
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();
}
增强的 Stream API
List<Integer> list = Arrays.asList(45, 43, 76, 87, 42, 77, 90, 73, 67, 88);
list.stream().takeWhile(x -> x < 50).forEach(System.out::println);
System.out.println();
list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
list.stream().takeWhile(x -> x < 5).forEach(System.out::println);
List<Integer> list = Arrays.asList(45, 43, 76, 87, 42, 77, 90, 73, 67, 88);
list.stream().dropWhile(x -> x < 50).forEach(System.out::println);
System.out.println();
list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
list.stream().dropWhile(x -> x < 5).forEach(System.out::println);
// 报NullPointerException
// Stream<Object> stream1 = Stream.of(null);
// System.out.println(stream1.count());
// 不报异常,允许通过
Stream<String> stringStream = Stream.of("AA", "BB", null);
System.out.println(stringStream.count());// 3
// 不报异常,允许通过
List<String> list = new ArrayList<>();
list.add("AA");
list.add(null);
System.out.println(list.stream().count());// 2
// ofNullable():允许值为null
Stream<Object> stream1 = Stream.ofNullable(null);
System.out.println(stream1.count());// 0
Stream<String> stream = Stream.ofNullable
iterate()重载的使用
这个 iterate 方法的新重载方法,可以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代。
// 原来的控制终止方式:
Stream.iterate(1, i -> i + 1).limit(10).forEach(System.out::println);
// 现在的终止方式:
Stream.iterate(1, i -> i < 100, i -> i + 1).forEach(System.out::println);
Optional获取Stream的方法
List<String> list = new ArrayList<>();
list.add("Tom");
list.add("Jerry");
list.add("Tim");
Optional<List<String>> optional = Optional.ofNullable(list);
Stream<List<String>> stream = optional.stream();
stream.flatMap(x -> x.stream()).forEach(System.out::println);
局部变量类型推断
开发者经常抱怨Java中引用代码的程度。局部变量的显示类型声明,常常被认为是不必须的,给一个好听的名字经常可以很清楚的表达出下面应该怎样继续。
使用局部类型推断,减少了啰嗦和形式的代码,避免了信息冗余,而且对齐了变量名,更容易阅读!
适用于情况:
//1.局部变量的初始化
var list = new ArrayList<>();
//2.增强for循环中的索引
for(var v : list) {
System.out.println(v);
}
//3.传统for循环中
for(var i = 0;i < 100;i++) {
System.out.println(i);
}
不适用情况:
- 初始值为null
- 方法引用
- Lambda表达式
- 为数组静态初始化
不适用以下的结构中:
情况1:没有初始化的局部变量声明
情况2:方法的返回类型
情况3:方法的参数类型
情况4:构造器的参数类型
情况5:属性
情况6:catch块
工作原理
在处理 var时,编译器先是查看表达式右边部分,并根据右边变量值的类型进行
推断,作为左边变量的类型,然后将该类型写入字节码当中。
注意点:
//示例1:
var list1 = List.of("Java", "Python", "C");
var copy1 = List.copyOf(list1);
System.out.println(list1 == copy1); // true
//示例2:
var list2 = new ArrayList<String>();
var copy2 = List.copyOf(list2);
System.out.println(list2 == copy2); // false
//示例1和2代码基本一致,为什么一个为true,一个为false?
从 源 码 分 析 , 可 以 看 出 copyOf 方 法 会 先 判 断 来 源 集 合 是 不 是
AbstractImmutableList 类型的,如果是,就直接返回,如果不是,则调用 of 创
建一个新的集合。示例2因为用的 new 创建的集合,不属于不可变 AbstractImmutableList 类的子类,所以 copyOf 方法又创建了一个新的实例,所以为false。
JDK 11 是一个长期支持版本(LTS, Long-Term-Support)。
新增了一系列字符串处理方法

Optional 加强

局部变量类型推断升级
在var上添加注解的语法格式,在jdk10中是不能实现的。在JDK11中加入了这样
的语法。
//错误的形式: 必须要有类型, 可以加上var
//Consumer<String> con1 = (@Deprecated t) ->
System.out.println(t.toUpperCase());
//正确的形式:
//使用var的好处是在使用lambda表达式时给参数加上注解。
Consumer<String> con2 = (@Deprecated var t) ->
System.out.println(t.toUpperCase());
全新的HTTP 客户端API

更简化的编译运行程序
看下面的代码。
// 编译
javac Javastack.java
// 运行
java Javastack
在我们的认知里面,要运行一个 Java 源代码必须先编译,再运行,两步执行动作。
而在未来的 Java 11 版本中,通过一个 java 命令就直接搞定了,如以下所示:
java Javastack.java
一个命令编译运行源代码的注意点:
ZGC
优势:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。