import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.URI;
import java.nio.file.*;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Signature;
import java.text.NumberFormat;
import java.time.*;
import java.time.temporal.ChronoUnit;
import java.time.zone.ZoneOffsetTransition;
import java.time.zone.ZoneRules;
import java.util.*;
import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class VersionTest {
    public static void main(String[] args) throws Exception {

        /////////////////////////////////// jdk8 ///////////////////////////////////

        // 0. 内存空间调整,永久代移除,改为元空间
        // 1. 引入 Optional
        Optional.ofNullable(null).ifPresent(System.out::println);
        Optional.of("Hello")
                .flatMap(s1 -> Optional.of("World").map(s2 -> s1 + " " + s2))
                .ifPresent(System.out::println);

        // 2. 支持调用Js(Nashorn在jdk11移除, jdk11之后推荐使用graal)
        // implementation("org.graalvm.js:js-scriptengine:24.2.2")
        // implementation("org.graalvm.polyglot:js:24.2.2")
        // https://www.graalvm.org/latest/reference-manual/js/ScriptEngine/
        ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("js");
        System.out.println("=== 数值公式计算测试 ===");

        // 简单数学表达式计算
        try {
            Object result1 = scriptEngine.eval("2 + 3 * 4");
            System.out.println("2 + 3 * 4 = " + result1); // 输出: 14

            Object result2 = scriptEngine.eval("(10 + 5) / 3");
            System.out.println("(10 + 5) / 3 = " + result2); // 输出: 5

            // 更复杂的数学计算
            Object result3 = scriptEngine.eval("Math.pow(2, 3) + Math.sqrt(16)");
            System.out.println("2^3 + √16 = " + result3); // 输出: 12

            // 使用变量的计算
            scriptEngine.eval("var a = 10; var b = 20; var result = a * b + (a + b);");
            Object result4 = scriptEngine.eval("result");
            System.out.println("a=10, b=20, a*b + (a+b) = " + result4); // 输出: 230

        } catch (ScriptException e) {
            System.err.println("数值计算出错: " + e.getMessage());
        }

        // 创建一个模板计算方法
        try {
            // 定义模板数据
            scriptEngine.eval("var x = 10;");
            scriptEngine.eval("var y = 5;");

            // 模拟模板处理
            String template = "{\"a\":\"1\",\"bal\":\"${x * y}\"}";
            System.out.println("原始模板: " + template);

            // 提取并计算公式
            Object calcResult = scriptEngine.eval("x * y");
            String processedTemplate = template.replace("${x * y}", calcResult.toString());
            System.out.println("处理后模板: " + processedTemplate);

        } catch (ScriptException e) {
            System.err.println("模板计算出错: " + e.getMessage());
        }

        // 性能测试:计算斐波那契数列
        System.out.println("=== 斐波那契数列计算测试 ===");
        long fibStart = System.currentTimeMillis();
        try {
            scriptEngine.eval("""
        function fibonacci(n) {
            if (n <= 1) return n;
            return fibonacci(n - 1) + fibonacci(n - 2);
        }
        var fibResult = fibonacci(10);
        """);
            Object fibResult = scriptEngine.eval("fibResult");
            System.out.println("斐波那契数列第10项: " + fibResult); // 输出: 55
            System.out.println("计算耗时: " + (System.currentTimeMillis() - fibStart) + "ms");

        } catch (ScriptException e) {
            System.err.println("斐波那契计算出错: " + e.getMessage());
        }

        // 3. 接口中支持默认定义方法 interface default method

        // 4. 引入了LocalDate/LocalDateTime
        // 本地时区
        LocalDateTime.now(ZoneId.of("America/Sao_Paulo"));
        System.out.println(ZoneId.systemDefault());
        ZonedDateTime time = ZonedDateTime.now(ZoneId.of("America/Sao_Paulo"));
        System.out.println(LocalDate.now());
        System.out.println(LocalDateTime.now());

// 跨时区应用需要注意
        // 统一存储时区为标准时区(UTC),如:JDBC/应用层设置默认时区为UTC
        // 前端传递带时区信息的时间数据,如:可使用ISO 8601格式:2023-01-01T10:00:00+08:00;或者分别传递时间和时区信息
        // 为了便于内地开发调试,将中国时间&UTC时间同时记录在日志中
        System.out.println(LocalDateTime.now());
        System.out.println(LocalDateTime.now(ZoneId.of("America/Sao_Paulo")));
        System.out.println(LocalDateTime.now(ZoneId.of("UTC")));
        System.out.println(ZonedDateTime.now());
        System.out.println(ZonedDateTime.now(ZoneId.of("America/Sao_Paulo")));
        System.out.println(ZonedDateTime.now(ZoneId.of("UTC")));

        // 夏令时(Daylight Saving Time,DST)是许多地区在夏季将时钟向前调整一个小时的做法
        // 夏令时是为了更好地利用日光而实行的制度:
        // 春季将时钟向前调整1小时(例如从 2:00 调整到 3:00)
        // 秋季将时钟向后调整1小时(例如从 2:00 调整到 1:00)
        // 问题示例:某些时间点不存在或重复
        LocalDateTime springForward = LocalDateTime.of(2023, 3, 12, 2, 30); // 美国夏令时开始
        ZonedDateTime zdt = springForward.atZone(ZoneId.of("America/New_York"));
        // 实际会变成 3:30,因为2:30在这一天不存在
        System.out.println(zdt);

        LocalDateTime fallBack = LocalDateTime.of(2023, 11, 5, 1, 30); // 美国夏令时结束
        ZonedDateTime zdt1 = fallBack.atZone(ZoneId.of("America/New_York"));
        // 这个时间存在两次:夏令时的1:30和标准时的1:30
        System.out.println(zdt1);

        ZoneRules rules2025 = ZoneId.of("America/New_York").getRules();
        LocalDateTime jan1 = LocalDateTime.of(2025, 1, 1, 0, 0);
        ZoneOffsetTransition transition = rules2025.nextTransition(jan1.atZone(ZoneId.of("America/New_York")).toInstant());
        System.out.println("2025年夏令时开始: " + transition);
        System.out.println(LocalDateTime.of(2025, 3, 9, 2, 30)
                .atZone(ZoneId.of("America/New_York")));

        // 错误的时间计算示例
        LocalDateTime start = LocalDateTime.of(2023, 3, 11, 10, 0); // 夏令时前一天
        ZonedDateTime startZoned = start.atZone(ZoneId.of("America/New_York"));
        System.out.println("2023年夏令时纽约时间: " + startZoned);
        System.out.println("2023年夏令时UTC时间: " + start.atZone(ZoneId.of("UTC")));
        System.out.println("2023年夏令时北京时间: " + start.atZone(ZoneId.of("Asia/Shanghai")));
        System.out.println("纽约时间: " + startZoned);
        System.out.println("对应UTC时间: " + startZoned.withZoneSameInstant(ZoneId.of("UTC")));
        System.out.println("对应北京时间: " + startZoned.withZoneSameInstant(ZoneId.of("Asia/Shanghai")));

        LocalDateTime end = LocalDateTime.of(2023, 3, 12, 10, 0); // 夏令时当天
        ZonedDateTime endZoned = end.atZone(ZoneId.of("America/New_York"));

        // 预期是24小时,但实际可能不是
        Duration duration = Duration.between(startZoned, endZoned);
        // duration 可能是23小时而不是24小时
        System.out.println(duration.toHours());

        // 5. 引入了Duration/Period
        System.out.println(Duration.ofDays(1));
        System.out.println(Duration.ofHours(1));
        System.out.println(Duration.ofMinutes(1));
        System.out.println(Duration.ofSeconds(1));
        System.out.println(Duration.ofMillis(1));
        System.out.println(Duration.ofNanos(1));
        System.out.println(Duration.of(1, ChronoUnit.DAYS));
        System.out.println(Duration.of(1, ChronoUnit.HOURS));
        System.out.println(Duration.of(1, ChronoUnit.MINUTES));
        System.out.println(Duration.of(1, ChronoUnit.SECONDS));
        System.out.println(Duration.of(1, ChronoUnit.MILLIS));
        System.out.println(Duration.of(1, ChronoUnit.NANOS));
        // 年份长度不固定(365或366天)
        // 月份长度不固定(28-31天) Duration 表示精确的时间量(精确到纳秒)而月份、年份等时间单位长度是可变的,导致下面函数会报错
//        System.out.println(Duration.of(1, ChronoUnit.MONTHS));
//        System.out.println(Duration.of(1, ChronoUnit.YEARS));
//        System.out.println(Duration.of(1, ChronoUnit.FOREVER));
        System.out.println(Period.ofDays(1));
        System.out.println(Period.ofWeeks(1));
        System.out.println(Period.ofMonths(1));
        System.out.println(Period.ofYears(1));
        System.out.println(Period.of(1, 1, 1));
        System.out.println(Period.of(1, 1, 1).getDays());
        System.out.println(Period.of(1, 1, 1).getMonths());
        System.out.println(Period.of(1, 1, 1).getYears());
        System.out.println(Period.of(1, 1, 1).get(ChronoUnit.DAYS));


        // 6. 流式API的引入
        Stream.ofNullable("hello").forEach(System.out::println);
        List<String> words = Arrays.asList("apple", "banana", "cherry", "apricot", "blueberry");
        // 按首字母分组
        Map<Character, List<String>> grouped = words.stream()
                .collect(Collectors.groupingBy(s -> s.charAt(0)));
        System.out.println(grouped);
        // 分区(满足条件/不满足条件)
        Map<Boolean, List<String>> partitioned = words.stream()
                .collect(Collectors.partitioningBy(s -> s.length() > 5));
        System.out.println(partitioned);
        System.out.println(words.stream().map(String::toUpperCase).collect(Collectors.groupingBy(s -> s.charAt(0)
                , Collectors.mapping(s -> s, Collectors.joining(",")))));

        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        System.out.println(numbers.stream().reduce(0, Integer::sum));
        System.out.println(numbers.stream().reduce(1, (a, b) -> a * b));
        System.out.println(numbers.stream().map(String::valueOf).reduce("", (a, b) -> a + "," + b).substring(1));
        System.out.println(numbers.stream()
                .map(String::valueOf)
                .peek(System.out::println)
                .filter(s -> !s.isEmpty())
                .peek(System.out::println)
                .collect(Collectors.toList()));

        /////////////////////////////////// jdk9 ///////////////////////////////////
        // 0. 模块化(JPMS)
        // module-info.java 是针对package的, package是针对Class的, Class是针对Field/Method的
        // 暴露包:export
        // 引入包:open
        // 默认包:requires static
        // transitive 等关键字

        // 1. 字符串实现压缩原理(char[] --> bytes[])

        // 2. -Xlog 启动参数
        // 完整的GC日志配置示例:java -Xlog:gc*=debug:gc.log:time,tags:filesize=100M,filecount=5 -jar myapp.jar
        // 仅记录错误和警告信息: java -Xlog:gc=warning:gc_error.log MyApp

        // 3. jshell 交互式Java Shell工具

        // 进程API增强/Optional增强/Stream增强
        System.out.println(ProcessHandle.current().pid());
        Stream.of(1,2,3,4,5).takeWhile(i -> i < 3).forEach(System.out::println);
        Stream.of(1,2,3,4,5).dropWhile(i -> i < 3).forEach(System.out::println);
        Optional.ofNullable(null).or(() -> Optional.of("Hello"))
                .ifPresentOrElse(System.out::println, () -> System.out.println("No value"));

        /////////////////////////////////// jdk10 ///////////////////////////////////
        // 0. 增加 局部变量 var定义,推测类型

        // 1. var 泛型和多个接口实现

        // 2. var lambda 支持访问匿名类自定义变量

        // 3. 容器支持,能更好识别容器的内存和CPU限制
        // docker run -m 1G openjdk:10 java -XX:+UseContainerSupport -jar app.jar


        /////////////////////////////////// jdk11 ///////////////////////////////////

        // 0. ZGC 垃圾回收器
        // java -XX:+UseZGC -Xmx2G MyApp

        // 1. 文件读写增强
        // Paths.get("relativePath") 默认使用当前工作目录作为相对路径的基准目录
        try (var reader = Files.newBufferedReader(Paths.get("gc.log"))) {
            reader.lines().forEach(System.out::println);
        }

        // 2. 飞行记录器 (-XX:+FlightRecorder 已变为标准用法,无需增加此参数)
        // java -XX:+FlightRecorder -XX:StartFlightRecording=duration=60s,filename=versiontest.jfr,settings=profile org.example.VersionTest
        // 运行完成后,使用 JMC 打开 versiontest.jfr 分析性能数据

        // 3. 字符串增强方法
        String str = " Hello, World!  \n";
        System.out.println(str.repeat(4));


        /////////////////////////////////// jdk12 ///////////////////////////////////
        // 0. 字符串增强
        // 正数增加空格/负数减少空格
        System.out.println(str.indent(6));
        System.out.println(str.transform(s -> s.indent(-2)).transform(String::stripTrailing).toUpperCase());

        // 1. switch 表达式 (预览特性)
        switch (Stream.of("Hello", "World").skip(new Random().nextInt(2)).findFirst().orElse("default")) {
            case "Hello" -> System.out.println("Hello");
            case "World" -> System.out.println("World");
            default -> System.out.println("default");
        }

        // 2. Shenandoah 垃圾收集器 (实验性)
        // java -XX:+UseShenandoahGC -Xmx2G MyApp

        // 3. 数字格式加强
        // 输出123M
        System.out.println(NumberFormat
                .getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT)
                .format(123456789));
        System.out.println(NumberFormat
                .getCompactNumberInstance(Locale.JAPAN, NumberFormat.Style.SHORT)
                .format(123456789));

        // 4. Collectors.teeing() Collectors方法增强
        String teeingRes = numbers.stream().collect(Collectors.teeing(
                Collectors.maxBy(Comparator.comparingInt(Integer::intValue)),
                Collectors.minBy(Comparator.comparingInt(Integer::intValue)),
                (max, min) -> min.map(Object::toString).orElse(null)
                        + " " + max.map(Object::toString).orElse(null)
        ));
        System.out.println(teeingRes);

        /////////////////////////////////// jdk13 ///////////////////////////////////

        // 0. 文本块,预览特性
        String text = """
                1. 创建一个文本块,并使用它来创建一个字符串。
                2. 创建一个文本块,并使用它来创建一个字符串。
                3. 创建一个文本块,并使用它来创建一个字符串。
                """;
        System.out.println(text);

        // 1. switch 增强预览
        System.out.println(switch (Stream.of(1,2,3,4,5,6,7).skip(new Random().nextInt(7)).findFirst().orElse(0)) {
            case 1, 2, 3, 4, 5 -> "Weekday";
            case 6, 7 -> "Weekend";
            default -> {
                yield "Unknown";
            }
        });

        // 2. Socket 增强,引入了NIO实现Socket API, 提高了性能和可维护性
//        try (Socket.builder().connect(new InetSocketAddress("www.baidu.com", 80))) {
//
//        }

        // 3. FileSystems.newFileSystem() 增强
        // 获取文件系统属性
        FileSystem fs = FileSystems.getDefault();
        Set<String> views = fs.supportedFileAttributeViews();
        System.out.println("支持的文件属性视图: " + views);

        // 获取文件存储信息
        Iterable<FileStore> fileStores = fs.getFileStores();
        for (FileStore store : fileStores) {
            try {
                System.out.println("存储名称: " + store.name());
                System.out.println("总空间: " + store.getTotalSpace());
                System.out.println("可用空间: " + store.getUsableSpace());
            } catch (IOException e) {
                System.err.println("获取存储信息出错: " + e.getMessage());
            }
        }

        // 读取 JAR 文件中的资源
//        try {
//            // 假设您的类路径中有 JAR 文件
//            FileSystem fs = FileSystems.newFileSystem(
//                    Paths.get("your-app.jar"),
//                    (ClassLoader) null
//            );
//
//            // 读取 JAR 中的文件
//            Path readme = fs.getPath("/README.md");
//            if (Files.exists(readme)) {
//                Files.lines(readme).forEach(System.out::println);
//            }
//
//            fs.close();
//        } catch (IOException e) {
//            System.err.println("处理JAR文件出错: " + e.getMessage());
//        }
        try {
            Path tempZip = Files.createTempFile("test", ".zip");
            URI uri = URI.create("jar:" + tempZip.toUri());

            try (FileSystem zipFS = FileSystems.newFileSystem(uri, Map.of("create", "true"))) {
                // 在 ZIP 中创建文件
                Path newFile = zipFS.getPath("/test.txt");
                Files.write(newFile, "Hello ZIP!".getBytes());
                System.out.println("成功在ZIP中创建文件");
            }

            Files.delete(tempZip); // 清理临时文件
        } catch (IOException e) {
            System.err.println("ZIP文件系统操作出错: " + e.getMessage());
        }

        // 4. AppCDS的全称是Application Class-Data Sharing。主要是用来在不同的JVM中共享Class-Data信息,从而提升应用程序的启动速度
        // java -XX:+UnlockDiagnosticVMOptions -XX:+AllowArchivingWithJavaAgent -XX:ArchiveClassesAtExit=/tmp/sharedarchive.jsa --enable-preview CDSHelloWorld

        /////////////////////////////////// jdk14 ///////////////////////////////////

        // 0. NPE 排查增强 -XX:+ShowCodeDetailsInExceptionMessages

        // 1. 增加record关键字修饰的类对象,对象中所有属性是final修饰的,属于 immutable对象,不要尝试修改值,会得到变异错误
        record Person(String name, int age) {

        }
        Object person = new Person("zhang san", 18);
        System.out.println(person);

        // 2. instanceof 模式匹配
        if (person != null && person instanceof Person p) {
            System.out.println(p.name + ":" + p.age);

        }

        // 3. 增强了飞行器生产性能监控套件 && JMC工具

        // 4. CMS垃圾回收期删除,G1垃圾收集器优化(并行化完全回收,内存分配优化)


        /////////////////////////////////// jdk15 ///////////////////////////////////

        // 0. 密封类,二次预览

        // 1. 隐藏类主要用于框架和库的动态类生成
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        try {
            Class<?> hiddenClass = lookup.defineHiddenClass(new byte[]{}, true).lookupClass();
        } catch (Exception e) {
            // 隐藏类特点,不能被其它类连接/不能被反射发现/当没有强引用时可以被垃圾回收
        } catch (Throwable t) {
            System.err.println(t.getMessage());
        }

        // 2. 使用 NIO 实现替代了传统的 DatagramSocket 实现
        try (DatagramSocket socket = new DatagramSocket()) {
            InetAddress address = InetAddress.getByName("localhost");
            DatagramPacket packet = new DatagramPacket(
                    "Hello".getBytes(), 5, address, 8080
            );
            socket.send(packet);
        }

        // 3.  EdDSA 算法支持
        // EdDSA 密钥生成和签名
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519");
        KeyPair kp = kpg.generateKeyPair();

        Signature sig = Signature.getInstance("Ed25519");
        sig.initSign(kp.getPrivate());
        sig.update("Hello, World!".getBytes());
        byte[] signature = sig.sign();
        System.out.println("EdDSA 签名: " + Base64.getEncoder().encodeToString(signature));

        /////////////////////////////////// jdk16 ///////////////////////////////////

        // 0. Vector API (孵化器模块)
        // Vector API 示例(需要添加 --add-modules jdk.incubator.vector)
//        VectorSpecies<Float> SPECIES = FloatVector.SPECIES_256;
//        float[] a = new float[1024];
//        float[] b = new float[1024];
//        float[] c = new float[1024];
//
//        int i = 0;
//        // 向量化操作
//        for (; i < SPECIES.loopBound(a.length); i += SPECIES.length()) {
//            FloatVector va = FloatVector.fromArray(SPECIES, a, i);
//            FloatVector vb = FloatVector.fromArray(SPECIES, b, i);
//            FloatVector vc = va.mul(vb);
//            vc.intoArray(c, i);
//        }
//
//        // 处理剩余元素
//        for (; i < a.length; i++) {
//            c[i] = a[i] * b[i];
//        }

        // 1. 支持 Unix 域套接字通道

        /////////////////////////////////// jdk17 ///////////////////////////////////
        // 0. 密封类

        // 1. 新随机数生成器API
        // 新的随机数生成器
        RandomGeneratorFactory<RandomGenerator> factory =
                RandomGeneratorFactory.of("L128X1024MixRandom");
        RandomGenerator generator = factory.create(42);
        // 生成随机数
        int randomInt = generator.nextInt(100);
        double randomDouble = generator.nextDouble();
        System.out.println(randomInt + "==>" + randomDouble);
        // 使用默认的随机数生成器
        RandomGenerator defaultGenerator = RandomGenerator.getDefault();
        System.out.println(defaultGenerator.nextInt(100) + "==>" + defaultGenerator.nextDouble());

        // 2. Foreign Function & Memory API (孵化器) 用于与本地代码和内存交互的 API

    }

    public sealed interface Shape
        permits Circle, Rectangle {
        double area();
    }

    public static non-sealed class Circle implements Shape {
        private final double radius;
        public Circle(double radius) {
            this.radius = radius;
        }
        @Override
        public double area() {
            return Math.PI * radius * radius;
        }
    }
    public static non-sealed class Rectangle implements Shape {
        private final double width;
        private final double height;
        public Rectangle(double width, double height) {
            this.width = width;
            this.height = height;
        }
        @Override
        public double area() {
            return width * height;
        }
    }

    public static class ShapePrinter {
        private final Shape shape;
        public ShapePrinter(Shape shape) {
            this.shape = shape;
        }
        public void print() {
            System.out.println("The area of the shape is " + shape.area());
        }
    }

}

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐