JAVA8-21版本新特性
一、 java8
1. Lambda / Stream
元素序列: 流以顺序方式提供特定类型的一组元素。流只会按需获取/计算元素。但它从不存储元素。源 ( Source ):流可以将集合,数组或 I/O 资源作为输入源。聚合操作: 流支持聚合操作,如 filter、map、limit、reduce、find、match 等管道 ( pipelining ):大多数流操作都返回流本身,以便可以对其结果进行流水线操作。这些操作称为 中间 操作,它们的功能是获取输入,处理它们并将输出返回到目标。collect() 方法是一个终端操作,通常在流水线操作结束时出现,以标记流的结尾。原子性迭代 ( Automatic iterations ): 与需要显式迭代的集合相比,流操作在内部对所提供的源元素进行迭代。
2. Base64
- Base64 解码
Base64.Decoder getDecoder() - Base64 编码
Base64.Encoder getEncoder()
3. 方法引用
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
public class LambdaTester {
public static void main(String[] args) {
LambdaTester tester = new LambdaTester();
tester.run();
}
public void run() {
List<String> list = Arrays.asList("Ram","Shyam","Kabir");
// 输出
list.forEach(System.out::println);
// 转换为大写
list.forEach(LambdaTester::upperAndPrint);
// 转换为小写并输出
list.forEach(this::lowerAndPrint);
}
public void lowerAndPrint(String s) {
System.out.println(s.toLowerCase());
}
public static void upperAndPrint(String s) {
System.out.println(s.toUpperCase());
}
}
4. 接口(interface)默认方法
5. Optional
-
Optional.ofNullable允许传递的参数为null
Optionala = Optional.ofNullable(value1); -
Optional.of如果传递的参数为null,则抛出NullPointerException
Optionalb = Optional.of(value2);
6. Nashorn JavaScript
- jjs 命令行工具,用于在控制台执行 javascript 代码
jjs> print('你好 !');
你好 !
jjs> 5 + 8
13
jjs> 8 / 5
1.6
- 在Java中调用JavaScript
// 创建JavaScript引擎的管理器,也就是创建一个ScriptEngineManager类的实例
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
// 通过JavaScript引擎的管理器获取一个JavaScript引擎,比如Java8中引入的Nashorn
ScriptEngine nashorn = scriptEngineManager.getEngineByName("nashorn");
String name = "HELLO WORLD!";
Integer result = null;
try {
// 调用获取到的引擎的eval()方法执行一些代码
nashorn.eval("print('" + name + "')");
result = (Integer) nashorn.eval("8 + 5 * 3");
} catch(ScriptException e) {
System.out.println("脚本执行失败: "+ e.getMessage());
}
System.out.println(result.toString());
- 在JavaScript中调用Java代码
创建一个hello.js文件,执行jjs hello.js命令运行
var BigDecimal = Java.type('java.math.BigDecimal');
function calculate(amount, percentage) {
var result = new BigDecimal(amount).multiply(new BigDecimal(percentage)).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_EVEN);
return result.toPlainString();
var result = calculate(568000000000000000023,13.9);
print(result);
7. 函数接口
/**
* 从Function方法引用中提取属性名的工具类
*/
public class PropertyNameExtractor {
/**
* 从Function<T, R>中提取对应的属性名(遵循JavaBean规范)
* @param propertyGetter 方法引用(如School::getName)
* @param <T> 对象类型
* @param <R> 属性类型
* @return 解析后的属性名(如"name")
* @throws Exception 解析失败时抛出(如非标准getter方法、非方法引用的Lambda)
*/
public static <T, R> String getPropertyName(Function<T, R> propertyGetter) throws Exception {
// 1. 空值校验
if (propertyGetter == null) {
throw new IllegalArgumentException("propertyGetter 不能为null");
}
// 2. 通过反射获取Lambda的SerializedLambda(核心:解析方法引用的底层信息)
Method writeReplaceMethod = propertyGetter.getClass().getDeclaredMethod("writeReplace");
writeReplaceMethod.setAccessible(true); // 突破访问权限
SerializedLambda serializedLambda = (SerializedLambda) writeReplaceMethod.invoke(propertyGetter);
// 3. 获取getter方法名(如"getName")
String getterMethodName = serializedLambda.getImplMethodName();
// 4. 遵循JavaBean规范,从getter方法名提取属性名
return resolvePropertyNameFromGetter(getterMethodName);
}
/**
* 从getter方法名解析属性名(JavaBean规范)
* - getXXX → xxx(首字母小写)
* - isXXX → xxx(布尔类型的getter,如isEnabled → enabled)
* @param getterMethodName getter方法名(如getName、isActive)
* @return 属性名
* @throws IllegalArgumentException 非标准getter方法时抛出
*/
private static String resolvePropertyNameFromGetter(String getterMethodName) {
String propertyName;
if (getterMethodName.startsWith("get")) {
// 处理getXXX:截取get后部分,首字母小写
propertyName = getterMethodName.substring(3);
} else if (getterMethodName.startsWith("is")) {
// 处理isXXX(布尔类型):截取is后部分,首字母小写
propertyName = getterMethodName.substring(2);
} else {
throw new IllegalArgumentException(
"非标准的JavaBean getter方法:" + getterMethodName + ",请使用getXXX或isXXX格式");
}
// 首字母小写(如Name → name,Active → active)
if (propertyName.isEmpty()) {
throw new IllegalArgumentException("getter方法名格式错误:" + getterMethodName);
}
return Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
}
}
8. 日期时间API
- LocalDate 、LocalTime 和 LocalDateTime。分别用于处理 本地日期、本地时间 和 本地日期时间。
二、 java9
1. 模块化
2. REPL(JShell)
- jshell, cmd执行
jshell命令,进入交互式环境,执行/help可以查看帮助信息 - 执行简单数学计算
jshell> 6 * 8
$4 ==> 48
jshell> 12 / 3
$5 ==> 4
jshell> $4
$4 ==> 48
jshell> $4 * $5
$7 ==> 192
- 函数定义
jshell> double circleArea(double r) {
...> return Math.PI * r * r;
...> }
| 已创建 方法 circleArea(double)
jshell> circleArea(2)
$10 ==> 12.566370614359172
- 退出
/exit
3. 改进 JavaDocs
- 新的 JavaDoc 文档格式
- 新添加的 JavaDoc 搜索功能
4. 集合不可变实例工厂方法
List.of()、Set.of()和Map.of()方法用于创建不可变的集合实例,这些方法在 Java 9 之前是私有的,现在它们被公开为公共 API。
List<String> list = List.of("a", "b", "c");
Set<String> set = Set.of("a", "b", "c");
Map<String, Integer> map = Map.of("a", 1, "b", 2, "c", 3);
Map < String, String > map1 = Map.ofEntries(new AbstractMap.SimpleEntry < > ("A", "Apple"), new AbstractMap.SimpleEntry < > ("B", "Boy"), new AbstractMap.SimpleEntry < > ("C", "Cat"));
5. 私有接口方法
6. 改进的 try-with-resources 语句
static String readData(String message) throws IOException {
Reader inputString = new StringReader(message);
BufferedReader br = new BufferedReader(inputString);
try (br) {
return br.readLine();
}
}
三、 java10
1. 局部变量类型推断
- var关键字
var list = new ArrayList<String>();
list.add("Hello");
list.add("World");
for (var str : list) {
System.out.println(str);
}
四、 java11
1. 单文件Java程序直接运行(无需先编译)
- 无需javac,直接运行java
2. String类新增高频实用方法
// 1. isBlank() 对比 isEmpty()
String blankStr = " ";
System.out.println(blankStr.isBlank()); // true
System.out.println(blankStr.isEmpty()); // false
// 2. lines() 处理多行文本
String multiLine = "Java 11\n新特性\nString方法";
multiLine.lines().forEach(line -> System.out.println("行:" + line));
// 3. strip() 处理Unicode空白
String unicodeBlank = "\u2000Java\u2000"; // 特殊Unicode空白
System.out.println(unicodeBlank.trim()); // \u2000Java\u2000(trim失效)
System.out.println(unicodeBlank.strip()); // Java(strip有效)
// 4. repeat() 重复字符串
System.out.println("Java".repeat(3)); // JavaJavaJava
3. Files 类简化文件读写
// 读取文件
String content = Files.readString(Paths.get("test.txt"));
// 写入文件(覆盖)
Files.writeString(Paths.get("test.txt"), "Java11 简化文件操作");
4. Optional.isEmpty()
Optional.isEmpty() 语义更清晰的空判断,替代 !optional.isPresent():
五、 java12
1. switch表达式
// 传统 switch(繁琐,需break,无法直接返回值)
public static String getSeasonOld(int month) {
String season;
switch (month) {
case 3: case 4: case 5:
season = "春季";
break;
case 6: case 7: case 8:
season = "夏季";
break;
default:
season = "未知";
}
return season;
}
// Java 12 预览:Switch 表达式(箭头语法,可返回值)
public static String getSeasonNew(int month) {
return switch (month) {
case 3,4,5 -> "春季"; // 多值合并,箭头直接返回
case 6,7,8 -> "夏季";
default -> "未知";
};
}
2. 数字格式化工具(CompactNumberFormat)
便捷格式化大数字(如将 1000 转为「1K」、1000000 转为「1M」),适合展示友好的数字文案。
3. Stream API 新增 Teeing Collector
合并两个收集器的结果,解决「一次流处理同时计算两个指标」的需求(比如同时求总和和平均值)。
六、 java13
1. 文本块(Text Blocks)
用 """ 包裹多行字符串,无需手动拼接 \n 和转义 ",大幅简化 JSON、SQL、HTML 等多行文本的编写。
String json = """
{
"name": "Java",
"version": "13"
}
""";
2. Switch表达式(第二次预览)
新增yield关键字,用于在复杂分支中返回值(替代预览版的 break 返回),语法更清晰。
public static int getScore(String level) {
return switch (level) {
case "A" -> 90;
case "B" -> 80;
// 复杂分支:用yield返回值
case "C" -> {
int base = 70;
yield base - 5; // 65 当return用
}
default -> 0;
};
}
七、 java14
1. Record类
Java 16(14/15 为预览版)正式引入Record,它是一种特殊的类,专门用于创建 “只存数据、无复杂逻辑” 的不可变载体(比如 DTO、VO、元组等)。它会自动为你生成 equals()、hashCode()、toString() 方法,并简化构造函数和字段的声明。
// 定义一个User Record,包含name和age两个字段
public record User(String name, int age) {}
// 使用
User user = new User("张三", 25);
- 紧凑构造器(参数验证 / 预处理)
public record User(String name, int age) {
public User {
if (name == null) {
throw new IllegalArgumentException("name不能为空");
}
if (age < 0) {
throw new IllegalArgumentException("age不能为负数");
}
}
}
- 支持静态成员
public record User(String name, int age) {
// 静态常量
public static final int MIN_AGE = 0;
// 静态工厂方法
public static User createDefaultUser() {
return new User("默认用户", 18);
}
}
- 实现接口
// 定义接口
public interface Printable {
void printInfo();
}
// Record实现接口
public record User(String name, int age) implements Printable {
@Override
public void printInfo() {
System.out.println("用户信息:" + name + "," + age + "岁");
}
}
- 支持继承
public record User(String name, int age) extends Person {}
2. 模式匹配 instanceof(预览)
简化「类型判断 + 强制类型转换」的嵌套逻辑,无需手动强转。
// 传统写法
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.length());
}
// Java 14 模式匹配
if (obj instanceof String s) {
System.out.println(s.length());
}
3. 精准空指针异常(NPE)
JVM 会在空指针异常信息中直接指出「哪个变量为空」,无需手动排查。
// Java 14 前 NPE 信息:NullPointerException
// Java 14 后 NPE 信息:NullPointerException: Cannot invoke "String.length()" because "s" is null
public static void npeDemo() {
String s = null;
System.out.println(s.length());
}
八、 java15
1. 密封类 Sealed Classes(预览)
限制类的继承 / 接口的实现,只允许指定的类继承当前类,增强代码的封装性和可维护性。
// 密封类:仅允许 Student 和 Teacher 继承 Person
public sealed class Person permits Student, Teacher {
private String name;
// 构造方法、方法...
}
// 允许继承的子类(需显式声明 final/non-sealed/sealed)
public final class Student extends Person {} // final:不可再继承
public non-sealed class Teacher extends Person {} // non-sealed:可被任意类继承
九、 java16
Java 16 是这些短期版本的「集大成者」,将前序版本的核心预览特性转正,同时新增实用功能。
十、 java17
- Java 17 作为 LTS 版本,核心价值是转正了密封类、instanceof 模式匹配等成熟预览特性,大幅简化代码并增强类型安全;
- 性能层面重点优化了 ZGC/Shenandoah GC,实现跨平台支持,适配大内存、低延迟场景;
- 实用优化中,UTF-8 作为默认字符集 解决了跨平台编码痛点,安全层面强封装内部 API、移除过时组件,提升整体稳定性和安全性。
十一、 java18
- Java 18 最实用的特性是内置简单 Web 服务器,无需编码即可快速搭建静态文件服务,大幅提升本地调试效率;
- 预览 / 孵化特性聚焦「高性能计算(Vector API)」和「文档优化(JavaDoc 代码片段)」,持续探索 Java 在高性能场景的能力;
- 底层优化重点是「弃用 Finalization 机制」「固化 UTF-8 API」,逐步淘汰老旧、有缺陷的 API,提升整体稳定性。
十二、 java19
1. 虚拟线程 → 首次预览
- 虚拟线程是 JVM 管理的轻量级线程,不绑定底层 OS 线程(传统 Thread 是 OS 线程的包装);
- 创建百万级虚拟线程仅占用少量内存(每个虚拟线程栈初始仅几 KB),而 OS 线程通常只能创建数千个;
- 适合 IO 密集型场景(如微服务接口、数据库查询、网络请求),线程等待 IO 时会自动释放底层 OS 线程,大幅提升系统吞吐量。
public class VirtualThreadDemo {
public static void main(String[] args) throws InterruptedException {
// ========== 方式1:直接启动虚拟线程 ==========
Thread.startVirtualThread(() -> {
System.out.println("简单虚拟线程运行中:" + Thread.currentThread().getName());
try {
Thread.sleep(1000); // 模拟IO等待(如数据库/网络请求)
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
// ========== 方式2:通过ThreadFactory创建 ==========
ThreadFactory virtualThreadFactory = Thread.ofVirtual().name("virtual-thread-", 1).factory();
Thread vt = virtualThreadFactory.newThread(() -> {
System.out.println("工厂创建的虚拟线程:" + Thread.currentThread().getName());
});
vt.start();
// ========== 方式3:虚拟线程池(高并发场景首选) ==========
// 自动为每个任务创建虚拟线程,用完自动回收
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
// 提交10000个IO密集型任务,无资源压力(传统线程池会OOM)
for (int i = 0; i < 10000; i++) {
int taskId = i;
executor.submit(() -> {
System.out.println("任务" + taskId + "运行在:" + Thread.currentThread().getName());
Thread.sleep(500); // 模拟IO等待
return taskId;
});
}
} // try-with-resources 自动关闭线程池,等待所有任务完成
// 主线程等待所有虚拟线程执行完毕
Thread.sleep(2000);
System.out.println("所有任务执行完成");
}
}
2. 记录模式 → 首次预览
增强模式匹配能力,支持解构记录类(Record),无需手动调用 getter 即可提取记录类的字段值,简化数据解构逻辑。
// 定义记录类
record User(int id, String name) {}
record Order(int orderId, User user) {} // 嵌套记录类
public class RecordPatternsDemo {
public static void main(String[] args) {
// 1. 基础解构:直接提取记录类字段
Object obj = new User(1001, "Java19");
if (obj instanceof User(int id, String name)) { // 解构User
System.out.println("用户ID:" + id + ",姓名:" + name); // 输出:用户ID:1001,姓名:Java19
}
// 2. 嵌套解构:提取多层记录类字段
Object orderObj = new Order(2001, new User(1001, "Java19"));
if (orderObj instanceof Order(int oid, User(int uid, String uname))) { // 嵌套解构
System.out.println("订单ID:" + oid + ",关联用户:" + uname); // 输出:订单ID:2001,关联用户:Java19
}
}
}
十三、 java20
1. 虚拟线程 → 二次预览
public class VirtualThreadV2Demo {
// 测试ThreadLocal在虚拟线程中的使用(Java 20优化点)
private static final ThreadLocal<String> TL = ThreadLocal.withInitial(() -> "初始值");
public static void main(String[] args) throws InterruptedException {
// 1. 虚拟线程设置未捕获异常处理器
Thread uncaughtThread = Thread.ofVirtual()
.name("uncaught-vt")
.uncaughtExceptionHandler((t, e) -> {
System.out.println("虚拟线程" + t.getName() + "异常:" + e.getMessage());
})
.unstarted(() -> {
throw new RuntimeException("测试未捕获异常");
});
uncaughtThread.start();
// 2. ThreadLocal在虚拟线程池中的使用(优化内存占用)
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 1000; i++) {
int taskId = i;
executor.submit(() -> {
TL.set("任务" + taskId);
System.out.println("虚拟线程" + Thread.currentThread().getName() + ":" + TL.get());
TL.remove(); // 建议手动移除,优化内存
Thread.sleep(100);
});
}
}
Thread.sleep(2000);
System.out.println("虚拟线程任务执行完成");
}
}
2. 记录模式 → 二次预览
核心优化是支持与 switch 模式匹配结合,并完善嵌套记录解构的语法,让数据解构逻辑更简洁、覆盖更多场景
// 示例代码(switch + 记录模式)
// 定义嵌套记录类
record Point(int x, int y) {}
record Circle(Point center, double radius) {}
record Rectangle(Point topLeft, Point bottomRight) {}
// 密封接口:仅允许Circle、Rectangle实现(结合Java 17密封类)
sealed interface Shape permits Circle, Rectangle {}
public class RecordPatternsV2Demo {
// 计算形状面积:switch + 记录模式解构
public static double calculateArea(Shape shape) {
return switch (shape) {
// 解构Circle:提取center(x,y)和radius
case Circle(Point(int x, int y), double r) -> Math.PI * r * r;
// 解构Rectangle:提取两个Point的坐标计算面积
case Rectangle(Point(int x1, int y1), Point(int x2, int y2)) ->
Math.abs((x2 - x1) * (y2 - y1));
// 默认分支(密封接口可省略,编译器会检查完整性)
default -> 0.0;
};
}
public static void main(String[] args) {
Shape circle = new Circle(new Point(0, 0), 5.0);
Shape rect = new Rectangle(new Point(0, 0), new Point(10, 5));
System.out.println("圆面积:" + calculateArea(circle)); // 78.5398...
System.out.println("矩形面积:" + calculateArea(rect)); // 50.0
}
}
十四、java21
1. 未命名模式和变量
用 _ 表示「不需要使用的变量 / 模式」,简化代码,避免定义无意义的变量名,提升可读性。
// 1. 未命名变量:忽略不需要的参数
public static int sumFirstTwo(int[] arr) {
return switch (arr.length) {
case 0 -> 0;
case 1 -> arr[0];
case 2 -> arr[0] + arr[1];
default -> {
// 忽略循环变量(仅遍历前两个元素)
int sum = 0;
for (int _ : arr) { // _ 表示不需要使用的循环变量
sum += arr[0] + arr[1];
break;
}
yield sum;
}
};
}
// 2. 未命名模式:忽略记录类中不需要的字段
record Person(String name, int age) {}
public static boolean isAdult(Object obj) {
// 只关心age,忽略name
return obj instanceof Person(_, int age) && age >= 18;
}
public static void main(String[] args) {
System.out.println(isAdult(new Person("张三", 20))); // true
}
2. 序列集合 → 正式版
新增 SequencedCollection/SequencedSet/SequencedMap 接口,统一处理「有序集合」的首尾操作,解决传统集合(如 List/Map)首尾操作 API 不统一、繁琐的问题。
import java.util.LinkedList;
import java.util.LinkedHashMap;
import java.util.SequencedCollection;
import java.util.SequencedMap;
public class SequencedCollectionsDemo {
public static void main(String[] args) {
// 1. SequencedCollection(LinkedList实现)
SequencedCollection<String> list = new LinkedList<>();
list.addLast("Java17");
list.addFirst("Java21");
System.out.println(list.getFirst()); // Java21
System.out.println(list.reversed()); // [Java17, Java21]
// 2. SequencedMap(LinkedHashMap实现)
SequencedMap<String, Integer> map = new LinkedHashMap<>();
map.put("Java8", 8);
map.put("Java17", 17);
map.put("Java21", 21);
System.out.println(map.firstEntry()); // Java8=8
System.out.println(map.lastEntry()); // Java21=21
System.out.println(map.reversed()); // {Java21=21, Java17=17, Java8=8}
}
}
3. 字符串模板 → 预览
替代繁琐的 String.format() 和字符串拼接(+/StringBuilder),支持直接嵌入表达式,且支持类型安全的模板处理器。
public class StringTemplatesDemo {
public static void main(String[] args) {
String name = "Java21";
int version = 21;
// 基础模板:`STR` 是默认处理器
String info = STR."Hello, \{name}! Version: \{version + 0}";
System.out.println(info); // Hello, Java21! Version: 21
// 类型安全模板(如SQL,需自定义处理器)
String sql = SQL."SELECT * FROM user WHERE name = \{name} AND age = \{21}";
System.out.println(sql); // 自动防SQL注入,参数化处理
}
}