浅尝jdk8~17新特性
·
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());
}
}
}
更多推荐



所有评论(0)