public class Demo{ public static void main(String[] args){ var score = 'C'; // 执行switch分支语句 String s = switch (score){ case 'A', 'B' -> "上等"; case 'C' -> "中等"; case 'D', 'E' -> "下等"; default -> { if (score > 100) { yield "数据不能超过100"; } else { yield score + "此分数低于0分"; } } } } }1.2 微基准测试套件
1.想定量地知道某个方法需要执行多长时间,以及执行时间和输入参数的相关性。
2.一个接口有两种不同实现,希望比较哪种实现性能更好。
<properties> <jmh.version>1.14.1</jmh.version> </properties> <dependencies> <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-core</artifactId> <version>${jmh.version}</version> </dependency> <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-generator-annprocess</artifactId> <version>${jmh.version}</version> <scope>provided</scope> </dependency> </dependencies>2).代码编写
import org.openjdk.jmh.annotations.*; // 堆代码 duidaima.com @State(Scope.Thread) public class MyBenchmark { @Benchmark @BenchmarkMode(Mode.All) public void testMethod() { try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } } @Benchmark @BenchmarkMode(Mode.All) public void testMethod2() { try { Thread.sleep(600); } catch (InterruptedException e) { e.printStackTrace(); } } } import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; public class BenchmarkRunner { public static void main(String[] args) throws Exception { Options opt = new OptionsBuilder() .include(MyBenchmark.class.getSimpleName()) .forks(1) .warmupIterations(5) .measurementIterations(5) .build(); new Runner(opt).run(); } } //以下这些方法都是JMH的一部分,可以在任何版本的JMH中使用。 //include(SimpleBenchmark.class.getSimpleName()) :这个方法表示你想要运行哪个类的基准测试。 //exclude("xxx") :这个方法表示你想要在基准测试中排除哪个方法。 //forks(1) :这个方法表示你想要进行多少轮的基准测试。每一轮测试都会在一个新的 JVM 进程中进行,以确保每轮测试的环境是独立的。 //warmupIterations(5) :这个方法表示你想要进行多少次预热迭代。预热迭代是为了让 JVM 达到稳定状态,预热迭代的结果不会被计入最终的基准测试结果。 //measurementIterations(5) :这个方法表示你想要进行多少次正式的基准测试迭代,这些迭代的结果会被用来计算基准测试的最终结果。结果输出(只截取了一部分)
相关注解
在 JDK12 之前,一旦开始执行垃圾收集,即使可能会超过 -XX:MaxGCPauseMillis 参数设定的值,也不会停止。JDK12 中,如果 G1 垃圾收集器有可能超过预期的暂停时间,则可以终止。G1 垃圾收集器发现反复标记过多的区域后,G1 就会切换到更增量的一种 Mix GC 。
它将待回收的集合分为两个部分:强制回收和可选回收。强制回收的部分是 G1 无法增量回收的部分(比如年轻代)也可以包含能增量回收的部分(比如老年代)来提升性能,它占待回收集合的 80% 。当 G1 回收完强制回收部分后,如果还有多余的时间,将会更细粒度的处理可选回收部分,每次只会处理一个区域,避免超过用户指定的时间。在处理完一个区域后,G1 会根据剩余的时间来决定是否继续处理剩余的可选部分。
JDK13 中,ZGC 也能够主动释放未使用内存给操作系统,但可以通过 -XX : -ZUncommit 参数来显示关闭此功能。ZGC 支持最大堆大小为 16TB ,可以满足大多数大型服务器的需求。
ZGC 是在 JDK11 中引入的垃圾回收器,但一直都是实验版本,在 JDK15 中正式上线,如果你的应用程序需要处理非常大的堆或者更低的暂停时间,那么 ZGC 可能是一个更好的选择。如果你对兼容性和稳定性有更高的要求,因为 G1 经过长时间的验证和优化,可能 G1 更适合。
var rs = "test".transform(s -> s + "Java").transform(s -> s.toUpperCase()); // TESTJAVAindent:该方法允许我们调整String实例的缩进。
String result = "Java\njava\ntest".indent(3); /*结果会缩进三格 Java java test */1.7 Files 新增 mismatch 方法
System.out.println(Files.mismatch(Path.of("a.txt"),Path.of("b.txt")));
NumberFormat fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); String result = fmt.format(1000); //1K var cnf = NumberFormat.getCompactNumberInstance(Locale.CHINA,NumberFormat.Style.SHORT); System.out.println(cnf.format(5_0000)); //"5万" System.out.println(cnf.format(7_9200)); //"7.9万" System.out.println(cnf.format(8_000_000)); //"800万" System.out.println(cnf.format(9L << 30)); //"96亿" System.out.println(cnf.format(6L << 50)); //"5637142兆" System.out.println(cnf.format(6L << 60)); //"6917529京"1.9 JDK17 支持到 Unicode13
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.charAt(int)" because "str" is null at com.qf.jdk14.Test.main(Test.java:11)1.11 文本块特性
String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" + "WHERE `CITY` = 'INDIANAPOLIS'\n" + "ORDER BY `ID`, `LAST_NAME`;"; //使用文本块语法 String query = """ SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB` WHERE `CITY` = 'INDIANAPOLIS' ORDER BY `EMP_ID`, `LAST_NAME`;"""; String html = "<html>\n" + " <body>\n" + " <p>Hello, world</p>\n" + " </body>\n" + "</html>\n"; //使用文本块语法 String html = """ <html> <body> <p>Hello, world</p> </body> </html> """;缩进示例
System.out.println(""" Hello, multiline text blocks! """); // 结果 // > Hello, // > multiline // > text blocks!1.12 重新实现旧版 Socket API
新的实现是 JDK13 中的默认实现,但是旧的实现还没有删除,可以通过设置参数 -Djdk.net.usePlainSocketImpl=true 来切换到旧版本。
Map<String, Object> data = new HashMap<>(); data.put("test", "111"); data.put("test2", 222);JDK16 之前需要先判断获取的 value 是否是 String ,再做强制类型转换:
Object value = data.get("test"); if (value instanceof String) { String s = (String) value; System.out.println(s.substring(1)); }在 JDK16 的增强之后,对于 instanceof 的判断以及类型转换可以合二为一了:
Object value = data.get("test"); if (value instanceof String s) { System.out.println(s.substring(1)); }1.15 档案类
public final class User { final String name; final int age; public User(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return age == user.age && Objects.equals(name, user.name); } @Override public int hashCode() { return Objects.hash(name, age); } }通过 Record 类方式,一句话就可以实现以上功能,代码如下:
public record User(String username, String password) {}在 JDK16 之前的版本中,我们不能在类名后面直接写参数来定义类的状态。这是 JDK16 引入 record 类的一个新特性。
public class App { public static void main(String[] args) { User user = new User("user", "123456"); System.out.println(user.username()); } }注意事项:
.Record 不允许 extends 继承其他类
sealed class Human permits Kyrie, LeBron, George { public void printName() { System.out.println("Default"); } } non-sealed class Kyrie extends Human { public void printName() { System.out.println("Bob"); } } sealed class LeBron extends Human { public void printName() { System.out.println("Mike"); } } final class George extends Human { public void printName() { System.out.println("Yannick"); } }在这个例子中,Human 是一个密封类,它只允许 Kyrie,LeBron 和 George 这三个类继承。这样,我们就可以更精确地控制哪些类可以继承 Human 类,从而提高代码的安全性和可读性。