JAVA 9
模块机制
当我们导入一个jar包做为依赖时(包括JDK官方库),实际上很多功能我们并不会用到,但是由于他们是属于同一个jar捆绑在一起,这样就会导致我们可能只用到一部分功能,但是需要引用一个完整的类库,实际上我们可以把用不到的类库排除掉,大大降低jar库的规模。
JAVA9 引入了模块机制来对这种情况进行优化,在之前我们的项目如下:
引入模块机制之后,如下:
可以看到,模块可以由一个或者多个在一起的Java包组成,通过江这些包分出不同的模块,我们就可以按照模块的方式进行管理了。这里我们创建一个新的项目,并在src目录下,搭建module-info.java文件表示此项目采用模块机制,我们可以在idea右键创建 module-info.java 文件
在 JAVA 9 如果不创建 module-info.java,则所有包都会被加载,若希望分的清楚,可以创建 module-info.java,一旦创建 module-info.java 则只会导入 JAVA9的部分基础包,如 Logger 类,以前用的是 java.util.logging 的,但创建 module-info.java 后只有 java.lang.System 下的,我们可以在 module-info.java 导入我们想用的
如果加了 module-info.java 则需要清楚了解你需要使用的包位于哪里,如果使用反射的话,没有导入这样的包会报错,如下对 String 做反射报错结果
JAVA9 的反射 API 封装和安全性得到了改进,如果模块没有明确授权给其他模块使用反射的权限,那么其他模块是不允许使用反射进行修改的,看来Unsafe类是完不成了。对于模块的机制具有以下四中类型:
- 系统模块:来自JDK和JRE的模块(官方提供的模块,比如我们上面用的),我们也可以直接使用 java --list-modules 命令来列出所有的模块,不同的模块会导出不同的包供我们使用。
- 应用程序模块:我们自己写的JAVA模块项目
- 自动模块:可能有些库并不是Java9以上的模块项目,这种时候需要做兼容了,默认情况下是直接导出所有的包,可以访问所有其他模块提供类,不然之前版本的库就用不了了。
- 未命名的模块:我们自己创建的一个Java项目,如果没有创建 module-info.java,那么会按照未命名模块进行处理,未命名模块同样可以访问所有其他模块提供的类,这样我们之前写的java8 代码才能政策地在java9以及之后的版本下运行。不过,由于没有使用java9的模块新特性,未命名模块只能默认暴露给其他未命名的模块和自动模块,应用程序模块无法访问这些(实际上就是传统java8以下的变成模式,因为没有模块只需要导包就行)
我们也可以自己写一些jar提供别人使用,在使用的时候使用 module-info.java 让控制哪些导入,哪些不导入
requires 还可以加 static 关键字,加了static之后,在编译的时候会依然有这个包,但是在运行的时候就会报找不到该包。
除了 exports 可以跟 to 关键字,代表暴露给谁,指明哪些包可以使用我这个包
当 a 使用了某些包后,默认 b 是不能使用 a 所使用的包的,也就是没有传递性,我们所导入包 requires 后面加 transitive 关键字让其把依赖传递
如果我们对 以上的 User 使用反射,也是不能直接使用的,会报错
需要使用 open 关键字对整个所需要反射的 module 进行描述,如果不想对 module 进行描述,也可以对 module 下的需要反射类所在的包进行 opens 描述
uses语句使用服务接口的名字,当前模块就会发现它,使用java.util.ServiceLoader类进行加载,必须是本模块中的,不能是其他模块中的.其实现类可以由其他模块提供.
JShell交互式编程
java9 为我们提供了一种交互式变成工具Jshell,你还别说,真有Python的味道
C:\Users\User>jshell
| 欢迎使用 JShell -- 版本 17.0.3.1
| 要大致了解该版本, 请键入: /help intro
jshell>
环境配置完成后,我们只需要输入 jshell 命令即可开启交互式编程了,它支持我们一条一条命令进行操作。比如我们来做一个简单的计算:
jshell> int a = 10
a ==> 10
jshell> int b = 10
b ==> 10
jshell> int c = a/b
c ==> 1
jshell>
使用 /vars 可以看到我们定义的所有变量
jshell> /vars
| int a = 10
| int b = 10
| int c = 1
我们也可以创一个方法,并通过 /method 方法列出所有方法,并调用方法
jshell> public int max(int a,int b){
...> return a > b? a: b;
...> }
| 已创建 方法 max(int,int)
jshell> /method
| int max(int,int)
jshell> max(19,20)
$5 ==> 20
接口中的private方法
在Java8中,接口中的方法支持添加 default 关键字来添加默认实现;而在java9中,接口再次得到强化,提供接口中可以存在私有方法。
package com.b;
public interface Test {
default void test(){
this.test1();
System.out.println("默认方法");
}
private void test1(){
System.out.println("私有方法");
}
static void test2(){
System.out.println("静态方法");
}
}
package com.b;
public class MainB implements Test {
public static void main(String[] args){
MainB mainB = new MainB();
mainB.test();
Test.test2();
}
}
私有方法
默认方法
静态方法
集合类新增工厂方法
在之前,如果我们想要快速创建一个Map可以通过以下方式
public static void main(String[] args){
Map<String,String> map = new HashMap(3);
map.put("key","value");
map = new HashMap<String,String>(3){{
put("key","value");
}};
}
在java9之后,我们可以直接通过 of 方法来快速创建,但是这种方式就不能使用 put 方法
Map<String, String> key = Map.of("key", "value");
改进的Stream API
public static void main(String[] args){
// java8 只能使用of,为null会报错
Stream.of(null).forEach(System.out::println);
// Java9 允许为null
Stream.ofNullable(null).forEach(System.out::println);
// java8 允许生成无限的数据,可以用limit限制
Stream.iterate(0,i -> i+1).limit(20).forEach(System.out::println);
// java9 变为使用表达式来限制 相当于 for (int i=0;i<20;i++)
Stream.iterate(0,i -> i < 20,i -> i + 1).forEach(System.out::println);
// java9 还增加了截断流, i < 10,生成 小于 10 的数据
Stream.iterate(0,i -> i < 20,i -> i + 1).takeWhile(i -> i>10).forEach(System.out::println);
// java9 还增加了删除流, i < 10,小于 10 的数据都被删掉,相当于值打印 i >= 10 的数据
Stream.iterate(0,i -> i < 20,i -> i + 1).dropWhile(i -> i>10).forEach(System.out::println);
}
其他小改动
java7新增了Try-with-resources(只有实现了 AutoCloseable 或 Closeable 接口的资源),JAVA9有对try 增强
public void java8(){
try (InputStream stream = Files.newInputStream(Paths.get("pom.xml"))){
stream....
}catch(Exception e){
e.printStackTrace();
}
}
public void java9() throws IOException {
InputStream stream = Files.newInputStream(Paths.get("pom.xml"));
try (stream){
for (int i = 0; i < 100; i++) {
System.out.println(stream.read());
}
}catch(Exception e){
e.printStackTrace();
}
}
Optional 增强
public void java8(){
String s = null;
Optional.ofNullable(s).ifPresent(str -> System.out.println("str = " + str));
}
public void java9() throws IOException {
String s = null;
// 类似于 if else
Optional.ofNullable(s)
.ifPresentOrElse(str -> System.out.println("str = " + str),() -> System.out.println("MainB.java9"));
}
public void java9_1() {
String s = null;
// 类似于 if else
Optional.ofNullable(s)
.ifPresentOrElse(str -> System.out.println("str = " + str),() -> System.out.println("MainB.java9"));
}