jdk9是新特性最多的,因为jdk8是一个稳定版本。
? ? ? ? 模块系统 (Module System) | Java9最大特性。它提供了类似于OSGI框架的功能,模块之间存在相互的依赖关系,可以导出一个公共的API,并且隐藏实现的细节。作用为减少内存的开销。 |
? ? ? JShell和Jlink | JShel是交互式Java编程环境。允许开发者在命令行界面中快速编写和测试Java代? 码。 Jlink用于生成自定义的Java运行时映像,可以包含或排除特定的模块。 |
不可变集合类工厂方法 | 可以更方便地创建不可变集合。 |
接口中的私有方法 | 接口可以包含私有方法。 |
try-with-resources改进 | 能够更好地处理异常和资源关闭。 |
平台日志API和服务 | 提供了新的平台日志API和服务。 |
垃圾回收器 | 新增了Shenandoah垃圾回收器,旨在提供更高效的垃圾回收。 |
Java9之前的问题:
1.运行时间长(JVM需要加载rt.jar不管其中的类是否被classloader加载 ,而模块化可以根据? ? ? 模块的需要加载程序运行需要的class)。
2.当代码库越来越大,创建复杂。
3.很难真正地对代码进行封装。
?模块(module)的概念,其实就是package外再裹一层,不声明默认就是隐藏。 模块化使得代码组? 织上更安全,因为它可以指定哪些部分可以暴露,哪些部分隐藏。
模块化做到了:
模块化的主要目的在于减少内存的开销。
只须必要模块,而非全部jdk模块,可简化各种类库和大型应用的开发和维护。
改进 Java SE 平台,使其可以适应不同大小的计算设备。
改进其安全性,可维护性,提高性能。
?jdk9模块化代码:
?? ? ? ?
?注意:导入外部的junit模块并使用,必须将当前模块导出。
? ? ? ?基本使用 | |
定义方法,使用方法 | ? ? ? ? ? ? ? ? ? |
查看当前Session内代码片段 | /list |
查看当前Session变量 | /vars |
查看当前Session下的方法 | /methods |
使用jshell代码没有受检异常 | |
退出 | /exit |
public interface demo2 {
/*
* jdk8之前接口中只允许有 公有静态常量和抽象方法
* */
//接口默认都是公有静态常量,也只能是共有静态常量
//public static final int num=1;
int num=1;
//接口默认方法都是公有抽象方法
//public abstract void method1();
void method1();
/*
* jdk8及其之后接口可以有静态方法和默认方法
* */
public static void method2(){//静态方法
System.out.println("接口中的静态方法");
}
public default void method3(){//默认方法
System.out.println("接口中的默认方法");
}
/*
* jdk9及其之后接口可以有私有方法
* private void method4(){}
* private static void method4(){}
*
* */
private void method4(){
System.out.println("接口中的私有方法");
}
}
在jdk8中,如下代码是报错的
??Comparator<Object> com = new Comparator<>() {
? ? @Override
? ? public int compare(Object o1, Object o2) {
? ? ? ? return 0;
? ? }
};
<>必须写类型。而在jdk9中,上述代码就不报错,这是对<>钻石运算符的一个升级。
Java 8 中,可以实现资源的自动关闭,但是要求执行后关闭的所有资源必须在try子句中初始化,否则编译不通过。
?Java 9 中,用资源语句编写try将更容易,我们可以在try子句中使用已经初始化过的资源,此时的资源是final的。
?Jdk9以前:
?Jdk9:?
?StringBuffer 和 StringBuilder也发生改变。
要创建一个只读、不可改变的集合,必须构造和分配它,然后添加元素,最后包装成一个不可修改的集合。
JAVA 9的方法:
public class demo04 {
public static void main(String[] args) {
//jdk9只读集合方法
List<String> list1=List.of("1","2","3");
//list1.add("aaa");不支持
System.out.println(list1);
Map<String,String> map=Map.of("a","aa","b","bb");
System.out.println(map);
}
}
jdk8读写数据需要边读边写,jdk9使用TransferTo直接读写进去。
public class demo05 {
public static void main(String[] args) {
/*
* takeWhile() 的使用
* 用于从 Stream 中获取一部分数据,接收一个 判断条件 来进行选择。
* 在有序的Stream 中,takeWhile 返回**从开头开始的尽量多的元素。
* t ->t<40 遇到第一个不小于40 的元素就停止输出
* */
List<Integer> list= Arrays.asList(10,20,30,40,30,20,10);
list.stream().takeWhile(t ->t<40).forEach(System.out::println);
List<Integer> list2 = Arrays.asList(1,2,3,4,5,6,7);
list2.stream().takeWhile(t->t<7).forEach(System.out::println);
System.out.println("---------------------");
/*
* dropWhile() 的 使用
* dropWhile 的行为与 takeWhile 相反,返回剩余的元素
* t ->t<40 遇到第一个大于40 的元素就开始输出
* */
list.stream().dropWhile(t ->t<30).forEach(System.out::println);
System.out.println("---------------------");
/*
* ofNullable() 的 使用
*Java 8 中 Stream 不能完全为null,否则会报空指针异常。
*Java 9 中的 ofNullable 方法允许我们创建一个单元素 Stream,
* 可以包含一个非空元素,也可以创建一个空Stream。
* */
//java 8
Stream<String> streams = Stream.of("AA","BB",null);//允许通过
//Stream<Object> stream2 = Stream.of(null);//不允许通过
//java 9
Stream<Object> stream3 = Stream.ofNullable(null);//允许通过
System.out.println("---------------------");
/*
* iterate() 重载的使用
* 可以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代。
* */
//原始方式
Stream.iterate(1,i->i+1).limit(5).forEach(System.out::println);
//增强方式
Stream.iterate(1,i->i<6,i->i+1).forEach(System.out::println);
}
}
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
list.add("赵六");
Optional<List<String>> optional =Optional.ofNullable(list);
//optional中只用一个元素 [张三, 李四, 王五, 赵六]
optional.stream().limit(2).forEach(System.out::println);
//flatMap(x->x.stream())将一个元素 [张三, 李四, 王五, 赵六],再变为一个一个的元素
optional.stream().flatMap(x->x.stream()).limit(2).forEach(System.out::println);
list.stream().limit(2).forEach(System.out::println);
}
}
在局部变量中使用时,这些情况不适用:初始值为null,方法引用,数组静态初始化,Lambda表达式。
public class demo01 {
public static void main(String[] args) {
//1.局部变量的初始化
var list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
//2.增强for循环中的索引
for (var v : list) {
System.out.println(v);
}
// 3.传统for循环中
for (var i = 0; i <3 ; i++) {
System.out.println(i);
}
/*
* 在局部变量中使用时,如下情况不适用:
* */
//初始值为null
var a=null;
//方法引用
var b=System.out::println;
//Lambda表达式
var c=()->Math.random();
//数组静态初始化
var arr={"1","2","2"}
//数组动态初始化可以
var arr2=new int[]{1,2,3};
}
}
注意: ?var 不是一个关键字,不需要担心变量名或方法名会与 var发生冲突。
jdk9 添加了 of ,jdk10新增copyOf方法,它们两个都用来创建不可变的集合。
不同之处:
public static void main(String[] args) throws Exception {
//若初始的list1为不可变集合,copyOf之后的List2==list1
var list1 = List.of("AA","BB","CC");
var list2 = List.copyOf(list1);
System.out.println(list1==list2);//true
//若初始的list3为普通集合,copyOf之后的List2!=list1
var list3 = new ArrayList<String>();
list3.add("AA");
list3.add("BB");
List<String> list4 = List.copyOf(list3);
System.out.println(list3==list4); //false
}
copyOf 方 法 会 先 判 断 来 源 集 合 是 不 是AbstractImmutableList 类型的。如果是,就直接返回;如果不是,则调用 of()方法 创建一个新的集合。
ZGC, A Scalable Low-Latency Garbage Collector(Experimental)ZGC, 这应该是JDK11最为瞩目的特性, 没有之一。 但是后面带了Experimental,说明这还不建议用到生产环境。
ZGC是一个并发, 基于region, 压缩型的垃圾收集器, 只有root扫描阶段会STW(stop the world), 因此GC停顿时间不会随着堆的增长和存活对象的增长而变长。
没有用到生产环境。
以很方便的将一个 Optional 转换成一个 Stream, 或者当一个空 Optional 时给它一个替代。
?
这是 Java 9 开始引入的一个处理 HTTP 请求的的 HTTP Client API,支持同步和异步,在 Java 11 中为正式可用状态,在java.net 包中。
它将替代仅适用于blocking模式的HttpURLConnection(HttpURLConnection是在HTTP 1.0的时代创建的,并使用了协议无关的方法),并提供对WebSocket 和 HTTP/2的支持。
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request =
HttpRequest.newBuilder(URI.create("http://www.baidu.com")).build();
HttpResponse.BodyHandler<String> responseBodyHandler = HttpResponse.BodyHandlers.ofString();
HttpResponse<String> response = client.send(request, responseBodyHandler);
String body = response.body();
System.out.println(body);
}
改进的NullPointerExceptions,jdk14以前空指针异常,会指出异常所在处。
jdk14之前空指针异常:
jdk14以后的空指针异常:
jdk15提供text block (文本块)功能,解决字符串多行换行问题:
public static void main(String[] args) {
//jdk15增加文本块
String str = """
hello
world
hahaha
""";
System.out.println(str);
}
解决switch语句的一些不规则性成为障碍:
比如case标签之间的默认控制行为
case块中的默认范围
无意义的break语句。
但底层还是原始的switch的代码。
public class demo01 {
public static void main(String[] args) {
int level = new Random().nextInt(4);
String str = null;
switch (level){
case 1-> str="优秀";
case 2 -> str="good";
case 3-> str="yiban";
}
System.out.println(str);
String str2 = switch (level){
//必须有default
case 1 -> "haohao";
case 2-> "good";
default -> "yiban";
};
System.out.println(str2);
int level2 = new Random().nextInt(12);
String jiJi = null;
switch (level2){
case 3,4,5 -> jiJi="chun";
case 6,7,8->jiJi="xia";
case 9,10,11->jiJi="qiu";
default -> jiJi="dong";
}
System.out.println(jiJi);
String strLeave=switch (level){
//必须有default
case 0,1,2->{
System.out.println("hhh");
yield "haohaohaoa";
}
default -> "jjjjj";
};
System.out.println(strLeave);
}
}