jdk8(2014 年 3 月 18 日发布的)至今,已经将近十年时间,是长期稳定的,但是由于现在springboot3的发布,已经强制需要使用JDK17。
JDK 9 新特性
模块机制(module-info.java)
我们在使用JDK8的时候,当导入一个jar包后,会引入很多的依赖,而我们会使用到的则仅仅是一小部分,通过模块化机制可定制化使用到的jar包,提高jar的利用率
// 声明模块
module DemoName {
// 声明依赖模块, transitive修饰符会导致依赖于当前模块的其他模块具有隐式依赖性。
requires transitive java.logging;
requires transitive java.transaction.xa;
requires transitive java.xml;
// 声明哪些包是可以被其它模块访问
exports demo1;
exports demo2;
// 使用语句(uses statement)和提供语句(provides statement)实现其服务
// 使用语句可以指定服务接口的名字,当前模块就会发现它,使用 java.util.ServiceLoader类进行加载
uses demo.Driver;
}
优势:
- 让Java SE程序更加容易轻量级部署。
- 强大的封装能力。
- 改进组件间的依赖管理,引入比jar粒度更大的Module。
- 改进性能和安全性。
新增Stream API & 集合工厂方法
JDK 9 为 Stream 新增了几个方法:dropWhile、takeWhile、ofNullable,为 iterate 方法新增了一个重载方法。
takeWhile
Stream
.iterate(0, i -> i < 20, i -> i + 1) // 可以直接指定 i < 20
.takeWhile(i -> i < 10) //当i小于10时正常通过,一旦大于等于10直接截断
//.dropWhile(i -> i < 10) // 和上面的相反, 直接丢弃满足条件的.
.forEach(System.out::println);
dropWhile
Stream
.iterate(0, i -> i < 20, i -> i + 1) // 可以直接指定 i < 20
//.takeWhile(i -> i < 10) //当i小于10时正常通过,一旦大于等于10直接截断
.dropWhile(i -> i < 10) // 和上面的相反, 直接丢弃满足条件的.
.forEach(System.out::println);
ofNullable
Stream
.of(null) //如果传入null会报错
.forEach(System.out::println);
//使用新增的ofNullable方法,这样就不会了,不过这样的话流里面就没东西了
Stream
.ofNullable(null)
.forEach(System.out::println);
集合工厂方法(不可变)
// 通过java.util.Set 创建 不可变 的集合实例
Set<String> set = Set.of("A", "B", "C");
// 通过java.util.List 创建 不可变 的集合实例
List<String> list = List.of("A", "B", "C");
// 通过k1,v1,k2,v2,...,形式创建
Map<String, String> map = Map.of("A","V1","B","v2","C","v3");
// 通过 Map.entry 形式创建
Map<Integer, String> map1 = Map.ofEntries (
Map.entry(1, "v1"),
Map.entry(2, "v2"),
Map.entry(3, "v3"));
改进版 Try-With Resources
try-with-resources 是 JDK 7 中一个新的异常处理机制,它能够很容易地关闭在 try-catch 语句块中使用的资源。try-with-resources 声明在 JDK 9 已得到改进。如果你已经有一个资源是 final 或等效于 final 变量,您可以在 try-with-resources 语句中使用该变量,而无需在 try-with-resources 语句中声明一个新变量。
static String readData(String message) throws IOException {
Reader reader = new StringReader(message);
BufferedReader br = new BufferedReader(reader);
// 不需要重新声明变量
try (br) {
return br.readLine();
}
}
Java 10 新特性
局部变量类型推断
public static void main(String[] args) {
// String a = "Hello World!"; 之前我们定义变量必须指定类型
var a = "Hello World!";
//现在我们使用var关键字来自动进行类型推断,因为完全可以从后面的值来判断是什么类型
}
Java 11 新特性
用于Lambda的形参局部变量语法
public static void main(String[] args) {
Consumer<String> consumer = (var str) -> {
};
Consumer<String> consumer1 = (String str) -> {
};
//=============================================
var str = "AB\nC\nD";
str.lines() //根据字符串中的\n换行符进行切割,分为多个字符串,并转换为Stream进行操作
.forEach(System.out::println);
var str = "ABCD";
//比如现在我们有一个ABCD,但是现在我们想要一个ABCDABCD这样的基于原本字符串的重复字符串
System.out.println(str.repeat(2)); //一个repeat就搞定了
String str = " A B C D ";
System.out.println(str.trim()); //去除首尾空格
System.out.println(str.strip()); //去除首尾空格
/**
* trim()可以去除字符串前后的半角空白字符
* strip()可以去除字符串前后的全角和半角空白字符
*/
System.out.println(str.stripLeading()); //去除首部空格
System.out.println(str.stripTrailing()); //去除尾部空格
}
全新的HttpClient使用
public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {
HttpClient client = HttpClient.newHttpClient(); //直接创建一个新的HttpClient
//现在只需要构造一个Http请求实体,就可以让客户端帮助我们发送出去了(实际上就跟浏览器访问类似)
HttpRequest request = HttpRequest.newBuilder().uri(new URI("https://www.baidu.com")).build();
//现在就可以把请求发送出去了,注意send方法后面还需要一个响应体处理器(内置了很多)这里我们选择ofString直接吧响应实体转换为String字符串
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
//来看看响应实体是什么吧
System.out.println(response.body());
}
Java 12-16 新特性
新的switch语法-Java 14
public static void main(String[] args) {
System.out.println(gradeNew(79));
}
public static String gradeNew(int score) {
score /= 10;
return switch (score) {
case 10, 9 -> "优秀";
case 8, 7 -> "良好";
case 6 -> "及格";
default -> "不及格";
};
}
// yield
public static String gradeNew2(int score) {
score /= 10;
return switch (score) {
case 10, 9 -> "优秀";
case 8, 7 -> "良好";
case 6 -> "及格";
default -> {
System.out.println("做了很多事情");
yield "不及格";
}
};
}
文本块(“”" )-Java 15
不需要转义等多余操作,打印台可直接打印换行字符等
public static void main(String[] args) {
var str = """
dsfds
sdfsg " > < !
dsfdsg dfsdf
""";
System.out.println(str);
}
instanceof语法-Java 16
原先还需要类型各种判断及强制转换
public class Demo {
private String name;
private int age;
public boolean equals(Object obj) {
if (obj instanceof Demo demo) {
return demo.name.equals(this.name);
}
return false;
}
}
Java 17 新特性
密封类型
在Java中,我们可以通过继承(extends关键字)来实现类的能力复用、扩展与增强。但有的时候,可能并不是所有的类我们都希望能够被继承。所以,我们需要对继承关系有一些限制的控制手段,而密封类的作用就是限制类的继承。
实际上在之前我们如果不希望别人继承我们的类,可以直接添加final关键字. 这样有一个缺点,如果添加了final关键字,那么无论是谁,包括我们自己也是没办法实现继承的,但是现在我们有一个需求,只允许我们自己写的类继承A,但是不允许别人写的类继承A,这时该咋写?在Java 17之前想要实现就很麻烦。
sealed class B permits C,D {
// sealed:关键字,表示此类为密封类型
// permits:后面的类为允许继承的类,双向的
}
final class C extends B {
}
// non-sealed主动放弃了密封特性:
non-sealed class D extends B {
}
//==================================================================================
sealed class B permits C,D {
// sealed:关键字,表示此类为密封类型
// permits:后面的类为允许继承的类,双向的
}
sealed class C extends B {
}
// non-sealed主动放弃了密封特性:
non-sealed class D extends B {
}
final class CC extends C{
}
//=======================================================================================
// 父
public sealed [abstract] [class/interface] 类名 [extends 父类] [implements 接口, ...] permits [子类, ...]{
//里面的该咋写咋写
}
// 子
public [final/sealed/non-sealed] class 子类 extends 父类 {
//必须继承自父类
//final类型:任何类不能再继承当前类,到此为止,已经封死了。
//sealed类型:同父类,需要指定由哪些类继承。
//non-sealed类型:重新开放为普通类,任何类都可以继承。
}
//我们也可以通过反射来获取类是否为密封类型:
public static void main(String[] args) {
Class<B> bClass = B.class;
Class<C> cClass = C.class;
Class<D> dClass = D.class;
System.out.println(bClass.isSealed()); // true
System.out.println(cClass.isSealed()); // false
System.out.println(dClass.isSealed()); // false
}