Java

领域

各LTS版本功能

Java 8 Java 11
函数式编程和Lambda表达式 新String API
Stream API 新File API
新Java Time API Lambda的本地var变量
接口可指定default method HttpClient API
Java Flight Recorder可免费使用
Java 17 Java 21
Sealed类 Virtual Thread
更多信息的NullPointerException Sequenced Collections
(语法糖)Record Simple Web Server
(语法糖)Instanceof模式匹配 (语法糖)Switch模式匹配
(语法糖)文本块 (语法糖)Enum常量
(语法糖)增强的switch - 可返回
ZGC

函数式编程和Lambda表达式

Java 8引入FunctionalInterface和Lambda表达式,允许开发者使用函数式编程风格来创建可复用的代码。

  • 只有一个抽象方法的接口称为函数接口。添加了@FunctionalInterface注释,以便我们可以将接口标记为功能接口。函数接口的主要好处是可以使用Lambda表达式来实例化它们并避免使用大量的匿名类实现。
  • java.util.function中定义了大量的有用的函数接口,例如Consumer<T>Function<T, R>Predicate<T>Supplier<T>等,并重构了Collection的API以支持流式处理以使用这些预定义好的函数接口。
  • 对象方法,static方法,构造方法(new)也可以通过::作为Lamdba表达式来调用。
import java.util.Arrays;

public class Example {

    public static void main(String[] args) {
        var list = Arrays.asList("a", "b", "c");
        list.stream().map(Uppercase::new).forEach(System.out::println);

        Example interview = new Example();
        list.stream().map(Uppercase::new).forEach(interview::println);

        interview.hello(s -> s + " World");
    }

    public void println(Uppercase uppercase) {
        System.out.println(uppercase);
    }

    public void hello(Handle h) {
        System.out.println(h.add("Hello"));
    }

    static void print(String s) {
        System.out.print(s);
    }

    @FunctionalInterface
    interface Handle {
        String add(String a);
    }

    public static class Uppercase {

        private final String s;

        public Uppercase(String s) {
            this.s = s;
        }

        @Override
        public String toString() {
            return s.toUpperCase();
        }
    }
}

JVM内存管理

JVM内存分成三部分:堆内存、非堆内存和元空间。

  • 堆内存:用于存放对象实例、数组等。可以通过-Xmx-Xms参数设置。如果不配置,默认使用系统可用内存的25%,可以通过-XX:InitialRAMPercentage-XX:MaxRAMPercentage设置。
  • 元空间:存储类和方法的信息,常量池,等。通过-XX:MetaspaceSize-XX:MaxMetaspaceSize设置。
  • 非堆内存:常用于NIO库的直接内存分配,native方法调用时使用的内存等。通过-XX:MaxDirectMemorySize设置。

容器中运行Java需要注意,在Java8u191和Java10以后,JDK才可以认知到分配给容器的内存和CPU限制。

如果发生Full GC次数过多或时间过长,则代表系统中有太多长期存在的对象被分配到老年代。如果这些对象都是临时的,但因为各种原因被长期使用而得不到释放(如内存泄漏或不正常的长时间运行的任务等),则要调整系统的实现以减少这些长期对象的产生。确保短期对象都在Young GC中被回收,确保老年代中的对象都是预期的长期运行的对象。

JVM启动参数

参数 解释 示例
-Xms 设置JVM启动时的初始堆内存大小。 -Xms512m 设置初始堆内存为512MB
-Xmx 设置JVM可以使用的最大堆内存大小。 -Xmx4g 设置最大堆内存为4GB
-Xss 设置每个线程的堆栈大小。 -Xss256k 设置每个线程的堆栈大小为256KB
-XX:NewRatio 设置年轻代(新生代)和老年代的比例。 -XX:NewRatio=3 表示老年代是新生代的3倍
-XX:SurvivorRatio 设置新生代中Eden区与Survivor区的大小比例。 -XX:SurvivorRatio=6 表示Eden:S0:S1=6:1:1
-XX:MetaspaceSize 设置元空间的初始大小。 -XX:MetaspaceSize=256m 设置元空间初始大小为256MB
-XX:MaxMetaspaceSize 设置元空间的最大大小,防止元空间无限制增长。 -XX:MaxMetaspaceSize=1g 设置元空间最大为1GB
-XX:+UseG1GC 启用G1垃圾收集器。 -XX:+UseG1GC 启用G1垃圾收集器
-XX:+PrintGCDetails 在GC时打印详细信息。 -XX:+PrintGCDetails 打印GC详细信息
-XX:+HeapDumpOnOutOfMemoryError 当发生内存溢出时导出堆信息。 -XX:+HeapDumpOnOutOfMemoryError 发生OOM时导出堆信息
-XX:MaxHeapFreeRatio 控制最大堆空闲比率。超过此比率,JVM会增大堆直到 -Xmx 的最大限制。 -XX:MaxHeapFreeRatio=70
-XX:MinHeapFreeRatio 控制最小堆空闲比率。低于此比率,JVM会减少堆的大小直到 -Xms 的最小限制。 -XX:MinHeapFreeRatio=40
-XX:MaxNewSize 设置年轻代的最大大小。 -XX:MaxNewSize=512m
-XX:InitialTenuringThreshold 设置对象从新生代晋升到老年代的年龄阈值。 -XX:InitialTenuringThreshold=7
-XX:MaxTenuringThreshold 设置对象在新生代的最大年龄,超过此年龄的对象会被移动到老年代。 -XX:MaxTenuringThreshold=15
-XX:+UseSerialGC 启用Serial垃圾收集器。 -XX:+UseSerialGC
-XX:+UseParNewGC 启用ParNew垃圾收集器。 -XX:+UseParNewGC
-XX:+UseParallelGC 启用Parallel垃圾收集器。 -XX:+UseParallelGC
-XX:+UseConcMarkSweepGC 启用CMS垃圾收集器。 -XX:+UseConcMarkSweepGC
-XX:+PrintGCApplicationStoppedTime 打印应用因垃圾收集而停顿的时间。 -XX:+PrintGCApplicationStoppedTime
-XX:+PrintHeapAtGC 在进行GC时打印堆的详细信息。 -XX:+PrintHeapAtGC
-XX:+PrintTenuringDistribution 打印对象在新生代中的年龄分布信息。 -XX:+PrintTenuringDistribution
-XX:+HeapDumpOnOutOfMemoryError 当出现内存溢出错误时,自动Dump堆信息。 -XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath 设置HeapDump的保存路径。 -XX:HeapDumpPath=/path/to/dump

参考资料

  • https://www.baeldung.com/java-11-new-features
  • https://medium.com/javarevisited/java-17-vs-java-11-exploring-the-latest-features-and-improvements-6d13290e4e1a
  • https://dzone.com/articles/whats-new-between-java-17-and-java-21