likes
comments
collection
share

java 6-21 重要的变动

作者站长头像
站长
· 阅读数 50

kotlin 成为了Android的首选语言,但是很遗憾,有的项目不能更换语言开发或者混合开发,但是在Android 开发中很容易忽略JDK的版本特性,因为它不像Android的版本特性一样总是被使用。JDK 这些年都增加了哪些新的功能和语法呢?

Java 6(2006年12月)

  1. 改进的 JIT 编译器: 增强了 Java 程序的性能。
  2. 脚本语言支持: 集成了对脚本语言的支持,特别是 JavaScript(通过 Rhino 引擎)。
  3. Java 编译 API: 提供了一组 API 用于编译 Java 源文件。
  4. 对 Web 服务的增强: 包括对 JAX-WS 2.0, JAXB 2.0 的支持。
  5. 改进的 Swing: 引入了桌面外观(SystemTray API)、桌面集成(Desktop API)和对 Windows Vista 的更好支持。
  6. Pluggable Annotation Processing API: 提供了一个新的 API 用于注解处理。
  7. 增强的监控和管理: 增加了对 JMX 和 JVM 的增强监控和管理能力。
  8. 垃圾收集改进: 包括并发标记扫描垃圾收集器(CMS)的改进。

Java 7(2011年7月)

  1. 语言增强(Project Coin):
    • Switch 支持字符串: switch 语句可以使用字符串。
    • 多捕获块: 可以在一个 catch 块中捕获多个异常。
    • Try-with-resources 语句: 自动管理资源关闭。
    • 钻石操作符: 推断泛型类型以简化代码。
    • 二进制字面量: 使用前缀 0b0B 表示二进制字面量。
    • 下划线分隔符: 数字字面量中可以使用下划线分隔符以提高可读性,例如 1_000_000
  2. Fork/Join 框架: 用于并行执行任务的新框架,旨在充分利用多处理器系统。
  3. NIO.2 文件 I/O: 新的文件 I/O API,提供更丰富的文件系统操作和改进的异常处理。
  4. 异步 I/O: 提供了异步文件通道和异步套接字通道。
  5. 增强的并发实用工具: 包括 PhaserTransferQueueConcurrentLinkedDeque
  6. 动态语言支持(InvokeDynamic): 改进 JVM 以更好地支持动态语言(如 JRuby 和 Groovy)。
  7. 安全增强: 提高了密码学和安全包的性能和灵活性。
  8. Java 核心类库的改进: 增强了基本库,如 java.util.Objects,提供了一些实用方法。

7以前基本没什么需要注意的,除了NIO这块。

Java 8(2014年3月)

  • Lambda 表达式: 支持函数式编程。
  • 函数式接口: 使用 @FunctionalInterface 注解。
  • Stream API: 处理集合的序列化操作。
  • 默认方法: 接口可以包含默认实现的方法。
  • 静态方法: 接口可以包含静态方法。
  • Optional 类: 避免空指针异常的容器类。
  • 新的日期和时间 API: 包括 LocalDate, LocalTime, LocalDateTime, ZonedDateTime 等。
  • Nashorn JavaScript 引擎: 更快的 JavaScript 引擎替代 Rhino。
  • 重复注解: 支持在同一位置重复使用注解。

8就不一样了,lambda、Stream API、Optional 开发中使用频率还是比较高的

Java 9(2017年9月)

  • 模块系统: 提供更好的封装性和依赖管理。
  • JShell: 交互式 Java REPL 工具。
  • 改进的 Javadoc: 包括搜索功能和 HTML5 支持。
  • 多版本 JAR: 支持在一个 JAR 文件中包含多个版本的类文件。
  • 增强的 Stream API: 添加了 takeWhile, dropWhile, iterate 方法。
  • 工厂方法: 用于创建不可变集合的快捷方法,如 List.of(), Set.of(), Map.of()

Java 10(2018年3月)

  • 局部变量类型推断: 使用 var 关键字。
  • 应用数据类共享(AppCDS): 改进的类加载性能。
  • 并行 Full GC for G1: G1 垃圾收集器的 Full GC 并行化。
  • Root Certificates: 默认包含根证书,简化 SSL 连接。

局部变量的类型推断, 这里需要和kotlin 做个对比

Java 10 的局部变量类型推断和 Kotlin 的类型推断在功能和实现上有许多相似之处,但也有一些显著的区别。以下是两者的详细对比:

Java 10 的局部变量类型推断

  1. 使用 var 关键字:

    • 只能在局部变量声明中使用,如方法内的局部变量、增强的 for 循环变量、try-with-resources 语句中的变量。
    • 语法示例:
      var list = new ArrayList<String>();
      for (var item : list) {
          System.out.println(item);
      }
      
  2. 类型推断的范围:

    • 只能在初始化时推断类型,必须在声明时赋值。
    • 不能用于类成员变量、方法参数或返回类型。
  3. 限制:

    • 无法改变变量的类型,推断类型是编译时确定的,不能使用 var 关键字来声明未初始化的变量。
    • var 不能用于 lambda 表达式和方法引用的参数。
  4. 目标:

    • 主要目的是简化代码的编写,减少样板代码,提高代码的可读性,同时保持 Java 的静态类型系统。

Kotlin 的类型推断

  1. 使用 valvar 关键字:

    • val 表示不可变变量,var 表示可变变量。Kotlin 可以在更多场景中使用类型推断,包括类成员变量、方法参数和返回类型。
    • 语法示例:
      val list = ArrayList<String>()
      for (item in list) {
          println(item)
      }
      
  2. 类型推断的范围:

    • 可以在很多地方使用类型推断,包括局部变量、类属性、函数返回类型等。
    • 不要求在声明时初始化,可以在函数参数、返回类型和类属性中使用类型推断。
  3. 灵活性:

    • Kotlin 的类型推断更为广泛和灵活,可以根据上下文推断类型。
    • 支持更复杂的类型推断,例如 lambda 表达式和返回类型推断。
  4. 目标:

    • 提供更简洁的语法,提高开发效率,减少样板代码,同时保持 Kotlin 的静态类型系统。

对比总结

  1. 使用场景和灵活性:

    • Java 10: 类型推断只能用于局部变量声明,且必须在声明时初始化。它不能用于类成员变量、方法参数和返回类型。
    • Kotlin: 类型推断的应用范围更广,几乎可以在任何地方使用类型推断,包括类成员变量、方法参数和返回类型。
  2. 关键字:

    • Java 10: 使用 var 关键字来表示局部变量的类型推断。
    • Kotlin: 使用 valvar 来分别表示不可变和可变变量,并在更多场景中使用类型推断。
  3. 静态类型系统:

    • 两者皆有: Java 和 Kotlin 都保持了静态类型系统,通过类型推断来简化代码,同时保持类型安全。
  4. 限制和特点:

    • Java 10: 局部变量类型推断主要是为了减少样板代码,限制较多,使用范围较窄。
    • Kotlin: 更加灵活和广泛的类型推断,允许在更多上下文中使用,并且支持更复杂的类型推断逻辑。

示例对比

Java 10 示例:

public class Main {
    public static void main(String[] args) {
        var list = new ArrayList<String>();
        list.add("Java");
        for (var item : list) {
            System.out.println(item);
        }
    }
}

Kotlin 示例:

fun main() {
    val list = ArrayList<String>()
    list.add("Kotlin")
    for (item in list) {
        println(item)
    }
}

总结

Java 10 的局部变量类型推断和 Kotlin 的类型推断都旨在简化代码编写,提高开发效率,但 Kotlin 的类型推断更为广泛和灵活。Java 的局部变量类型推断则更为保守和有限,主要聚焦于局部变量声明,确保不改变 Java 语言的静态类型特性和向后兼容性。

Java 11(2018年9月)

  • 新的字符串方法: isBlank, lines, strip, stripLeading, stripTrailing, repeat
  • 运行 Java 文件: 使用 java 命令直接运行 .java 文件。
  • 局部变量语法的 lambda 参数: lambda 参数支持 var
  • HttpClient: 新的 HttpClient API 用于 HTTP/2 和 WebSocket 支持。
  • ZGC(Z Garbage Collector): 低延迟垃圾收集器。

Java 11 引入了一些新的字符串方法,包括 isBlank, lines, strip, stripLeading, stripTrailing, repeat。下面是这些方法的具体用法:

  1. isBlank(): 判断字符串是否为空白(只包含空格、制表符、换行符等空白字符)。

    String str = "   ";
    System.out.println(str.isBlank());  // 输出 true
    
  2. lines(): 将字符串拆分为行,返回一个流(Stream)。 可以拆分\n \r 或者\n\r这种

    String str = "Hello\nWorld\nJava";
    str.lines().forEach(System.out::println);
    // 输出:
    // Hello
    // World
    // Java
    
  3. strip(): 去除字符串两端的空白字符(空格、制表符、换行符等)。

    String str = "  Hello World  ";
    System.out.println(str.strip());  // 输出 "Hello World"
    
  4. stripLeading(): 去除字符串开头的空白字符。

    String str = "  Hello World";
    System.out.println(str.stripLeading());  // 输出 "Hello World"
    
  5. stripTrailing(): 去除字符串末尾的空白字符。

    String str = "Hello World  ";
    System.out.println(str.stripTrailing());  // 输出 "Hello World"
    
  6. repeat(int count): 将字符串重复指定次数。

    String str = "Java ";
    System.out.println(str.repeat(3));  // 输出 "Java Java Java "
    

这些新的字符串方法可以使字符串操作更加方便和灵活,特别是在处理文本数据时,可以更容易地进行格式化、清理和处理。

Java 12(2019年3月)

  • 增强的 switch 语句(预览): switch 语句可以返回值,并简化语法。
  • JVM 常量 API: 新的 API 用于描述常量池中的常量。
  • G1 垃圾收集器改进: 改进的暂停时间。

Java 12 引入了增强的 switch 语句,允许 switch 语句返回一个值,并简化了语法。这个功能提供了一种更简洁、更灵活的方式来处理多路分支逻辑。下面是它的具体用法:

public class Main {
    public static void main(String[] args) {
        int day = 3;
        String dayString = switch (day) {
            case 1 -> "Monday";
            case 2 -> "Tuesday";
            case 3 -> "Wednesday";
            case 4 -> "Thursday";
            case 5 -> "Friday";
            default -> throw new IllegalArgumentException("Invalid day of the week: " + day);
        };

        System.out.println("Today is " + dayString);
    }
}

在这个例子中,switch 语句根据 day 的值执行不同的分支,并将结果赋给 dayString 变量。这里的新语法包括:

  • 使用 -> 替代了 case 关键字后的冒号。
  • 语句块中的最后一个表达式会作为整个 switch 语句的结果返回。
  • 可以使用 yield 关键字来显式返回值,但这是可选的,如果没有 yield,则会隐式地返回语句块的最后一个表达式的值。

这种增强的 switch 语句简化了多路分支逻辑的编写,使代码更加清晰易读。它还允许 switch 语句作为表达式使用,从而在更多情况下简化代码。

Java 13(2019年9月)

  • 文本块(预览): 多行字符串文字。
  • 动态 CDS 档案: 改进的类数据共享。
  • ZGC 改进: 支持解除未使用的内存。

Java 14(2020年3月)

  • Switch 表达式: switch 语句的新语法已正式发布。
  • 记录类型(预览): 简化数据载体类的定义。
  • 模式匹配(预览): instanceof 操作符的模式匹配。

instanceof 操作符的模式匹配。这个功能使得对对象进行类型检查和类型转换变得更加简洁和易读。下面是一个示例:

public class Main {
    public static void main(String[] args) {
        Object obj = "Hello, world!";

        if (obj instanceof String str) {
            System.out.println("obj 是一个字符串: " + str);
            // 在这里可以直接使用 str 变量,它已经被声明为 String 类型
            int length = str.length();
            System.out.println("字符串长度为:" + length);
        } else {
            System.out.println("obj 不是一个字符串");
        }
    }
}

在这个示例中,我们使用 instanceof 操作符进行类型检查,并且将匹配的结果赋值给了一个新的变量 str。如果 obj 是一个 String 类型的实例,那么 str 变量就会被声明为 String 类型,并且可以直接在 if 语句的代码块中使用。这样,我们就避免了在 if 语句中进行类型转换的繁琐操作,使代码更加简洁和易读。

重点是判断类型后不用强转,之前我们使用时是需要强转的。

Java 15(2020年9月)

  • 文本块: 多行字符串文字成为正式功能。
  • 隐藏类: 用于框架的动态类生成。
  • ZGC 改进: ZGC 的多项性能改进。
  • Sealed 类(预览): 控制哪个类可以继承某个类。

Sealed 类,这是一种控制继承关系的机制,可以限制哪些类可以继承某个类。通过将一个类声明为 sealed,可以明确指定允许继承它的类,并对其他类进行限制。这个功能有助于提高代码的安全性和可维护性,减少意外的继承和扩展,从而降低代码的复杂度。下面是一个示例:

public sealed class Shape permits Circle, Rectangle, Triangle {
    // Shape 类的定义
}

public final class Circle extends Shape {
    // Circle 类的定义
}

public final class Rectangle extends Shape {
    // Rectangle 类的定义
}

public final class Triangle extends Shape {
    // Triangle 类的定义
}

在这个示例中,我们首先声明了一个 sealed 类 Shape,并通过 permits 关键字明确指定了允许继承它的子类。在这个例子中,Shape 类允许被继承的子类有 CircleRectangleTriangle。其他类不被允许继承 Shape,如果有其他类尝试继承 Shape,编译器会报错。

通过使用 Sealed 类,可以更加精确地控制继承关系,防止不合理的类继承和扩展,从而提高代码的安全性和可维护性。需要注意的是,Sealed 类是一个预览功能,可能会在未来的版本中发生变化,因此在实际项目中使用时需要谨慎考虑,并且可能需要等到它成为稳定特性后才能广泛应用。

Java 16(2021年3月)

  • 记录类型: 记录类型成为正式功能。
  • 强封闭 JDK: 更严格的封装 JDK 内部 API。
  • 模式匹配(instanceof): instanceof 模式匹配成为正式功能。

Java 17(2021年9月,长期支持版本)

  • Sealed 类: 控制哪个类可以继承某个类成为正式功能。
  • 增强的 switch 语句: switch 表达式成为正式功能。
  • 新 JEP 集合: 包括改进的伪随机数生成器、增强的 Foreign Function & Memory API、上下文自适应 G1ZGC 等。

Java 18(2022年3月)

  • UTF-8 默认字符集: 默认字符集改为 UTF-8。
  • 简单的 Web 服务器: 方便测试和开发的小型 Web 服务器。
  • 代码段的 Javadoc: 在 Javadoc 中嵌入代码段。

Java 19(2022年9月)

  • 虚拟线程(预览): 更轻量级的线程实现,改进并发性能。
  • 结构化并发(预览): 简化并发任务管理。
  • 外部函数和内存 API(预览): 更好的本地代码调用支持。
  • 模式匹配: 增强的模式匹配功能。

Java 20(2023年3月)

  • 记录模式(预览): 用于解构记录的模式匹配。
  • 模式匹配 for switch(第三个预览): 继续改进和完善 switch 语句的模式匹配。
  • 外部函数和内存 API(第二个预览): 继续改进和完善。

一种用于解构记录的模式匹配方式。记录模式使得在模式匹配中可以更方便地访问记录中的字段,并且可以根据记录的结构进行匹配和解构。下面是一个简单的示例,展示了如何使用记录模式:

public record Point(int x, int y) {}

public class Main {
    public static void main(String[] args) {
        Point point = new Point(10, 20);

        if (point instanceof Point p) {
            System.out.println("x = " + p.x() + ", y = " + p.y());
        }
    }
}

在这个示例中,我们定义了一个名为 Point 的记录(record),包含两个字段 xy。然后,我们创建了一个 Point 对象,并使用模式匹配检查它是否是一个 Point 类型的实例,并将其解构为变量 p。如果匹配成功,则打印出 xy 字段的值。

记录模式使得在 Java 中更方便地处理记录类型的数据,可以通过模式匹配的方式轻松地解构记录,并访问其中的字段。

Java 21(2023年9月,长期支持版本)

  • 虚拟线程: 作为正式功能发布,更轻量级的线程实现。
  • 结构化并发: 作为正式功能发布,简化并发任务管理。
  • 记录模式: 作为正式功能发布,用于解构记录的模式匹配。
  • 模式匹配 for switch: 作为正式功能发布,增强 switch 语句的模式匹配。
  • 外部函数和内存 API: 作为正式功能发布,更好的本地代码调用支持。
  • 字符串插值: 通过直接在字符串中插入变量和表达式,简化字符串操作。

让我们逐个解释并提供代码示例来说明每个功能:

虚拟线程

虚拟线程是 Java 21 中的一项正式功能,它是一种更轻量级的线程实现,旨在提高并发性能和资源利用率。虚拟线程是通过 Executors.newVirtualThreadExecutor() 方法创建的,可以与传统的线程一起使用,但是更轻量级。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
        for (int i = 0; i < 10; i++) {
            executor.submit(() -> {
                System.out.println("Hello from virtual thread: " + Thread.currentThread());
            });
        }
        executor.shutdown();
    }
}

这是一个虚拟线程线程池的演示,虚拟线程有得搞,可以单独学习一下,然后其他的还行1.8中的lambda、Stream API、Optional也是常搞的API

结构化并发

结构化并发是 Java 21 中的一项正式功能,它旨在简化并发任务的管理。通过结构化并发,可以更轻松地管理并发任务的执行和结果处理,提高代码的可读性和可维护性。

import java.util.concurrent.CompletableFuture;

public class Main {
    public static void main(String[] args) {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            System.out.println("Running in parallel");
        });

        future.thenRun(() -> {
            System.out.println("After completion");
        }).join();
    }
}

记录模式

记录模式是 Java 21 中的一项正式功能,它用于解构记录的模式匹配。记录模式使得在模式匹配中可以更方便地访问记录中的字段,并根据记录的结构进行匹配和解构。

public record Point(int x, int y) {}

public class Main {
    public static void main(String[] args) {
        Point point = new Point(10, 20);

        if (point instanceof Point p) {
            System.out.println("x = " + p.x() + ", y = " + p.y());
        }
    }
}

模式匹配 for switch

模式匹配 for switch 是 Java 21 中的一项正式功能,它增强了 switch 语句的模式匹配能力,使得在 switch 语句中可以更方便地进行模式匹配操作。

public class Main {
    public static void main(String[] args) {
        Object obj = "Hello";

        switch (obj) {
            case String s -> System.out.println("String: " + s);
            case Integer i -> System.out.println("Integer: " + i);
            default -> System.out.println("Unknown type");
        }
    }
}

外部函数和内存 API

外部函数和内存 API 是 Java 21 中的一项正式功能,它提供了更好的本地代码调用支持,使得在 Java 中更容易地调用本地代码并处理本地内存。

import jdk.incubator.foreign.*;
import static jdk.incubator.foreign.CLinker.*;

public class Main {
    public static void main(String[] args) throws Exception {
        MemorySegment segment = CLinker.toCString("Hello, world!");

        try (var scope = ResourceScope.newConfinedScope()) {
            var printfFn = CLinker.getInstance().lookup("printf", 
                FunctionDescriptor.ofVoid(CLinker.C_POINTER), 
                FunctionDescriptor.ofVoid(CLinker.C_POINTER)
            );
            printfFn.invokeExact(scope, "%s%n", segment);
        }
    }
}

字符串插值

字符串插值是 Java 21 中的一项正式功能,它通过直接在字符串中插入变量和表达式,简化了字符串操作,提高了代码的可读性和可维护性。

public class Main {
    public static void main(String[] args) {
        String name = "Alice";
        int age = 30;
        String message = String.format("Hello, my name is %s and I am %d years old.", name, age);
        System.out.println(message);
    }
}
转载自:https://juejin.cn/post/7379431208429584393
评论
请登录