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
    Optional a = Optional.ofNullable(value1);

  • Optional.of 如果传递的参数为null,则抛出NullPointerException
    Optional b = 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注入,参数化处理
    }
}