• Java21 LTS版本


    一、前言

    除了众所周知的 JEP 之外,Java 21 还有更多内容。首先请确认 java 版本:

    1. $ java -version
    2. openjdk version "21" 2023-09-19
    3. OpenJDK Runtime Environment (build 21+35-2513)
    4. OpenJDK 64-Bit Server VM (build 21+35-2513, mixed mode, sharing)

    我们一起来看看 String 和它的朋友们 Collections、Date、Time、HttpClient、并发、Math 和 BigInteger 的新增一些 API。

    二、String(Java21新增)

    String 新增了 indexOf() 方法,允许在起始索引和结束索引之间查找单个字符或子字符串。

    1. public int indexOf(int ch, int beginIndex, int endIndex);
    2. public int indexOf(String str, int beginIndex, int endIndex);

    示例:

    1. String text = "牛牛帮";
    2. int index = text.indexOf("0", 5, 15);

    三、Character(Java21新增)

    Character 类新增了几个方法来支持 Emoji 表情符号,新增了五个方法:isEmoji()isEmojiComponent()isEmojiModifier()isEmojiModifierBase() 和 isEmojiPresentation()

    1. public static boolean isEmoji(int codePoint);
    2. public static boolean isEmojiPresentation(int codePoint);
    3. public static boolean isEmojiModifier(int codePoint);
    4. public static boolean isEmojiModifierBase(int codePoint);
    5. public static boolean isEmojiComponent(int codePoint);
    6. public static boolean isExtendedPictographic(int codePoint);

    所有这些方法都接受一个 int 类型的码点作为参数,判断传入的码点是否具有对应的表情符号。

    四、StringBuffer 和 StringBuilder(Java21新增)

    StringBuffer 和 StringBuilder 新增了 repeat() 方法重复单个字符或字符串多次。

    StringBuilder:

    1. @Override
    2. public StringBuilder repeat(int codePoint, int count);
    3. @Override
    4. public StringBuilder repeat(CharSequence cs, int count);

    StringBuffer:

    1. @Override
    2. public synchronized StringBuffer repeat(int codePoint, int count);
    3. @Override
    4. public synchronized StringBuffer repeat(CharSequence cs, int count);

    五、Charset(Java18)

    Charset 新增了一个带 fallback 的 forName()方法。

    public static Charset forName(String charsetName, Charset fallback);

    六、正则分组优化(Java20)

    提取地址中的省市区县,代码如下:

    1. 笔者有幸用过正则分组,需求是提取地址中的省市区县,代码如下:
    2. private static final Pattern PATTERN = Pattern.compile("(?[^省]+自治区|.*?省|.*?行政区|.*?市)(?[^市]+自治州|.*?地区|.*?行政单位|.+盟|市辖区|.*?市|.*?县)(?[^县]+县|.+区|.+市|.+旗|.+海域|.+岛)?(?[^区]+区|.+镇)?(?.*)");
    3. public static Map getAddressResolution(String address) {
    4. Matcher matcher = PATTERN.matcher(address);
    5. String province, city, county, town, village;
    6. Map row = new HashMap<>();
    7. while (matcher.find()) {
    8. province = matcher.group("province");
    9. row.put("province", province == null ? "" : province.trim());
    10. city = matcher.group("city");
    11. row.put("city", city == null ? "" : city.trim());
    12. county = matcher.group("county");
    13. row.put("county", county == null ? "" : county.trim());
    14. town = matcher.group("town");
    15. row.put("town", town == null ? "" : town.trim());
    16. village = matcher.group("village");
    17. row.put("village", village == null ? "" : village.trim());
    18. }
    19. return row;
    20. }
    21. public static void main(String[] args) {
    22. String address = "湖南省长沙市岳麓区永青路668号";
    23. System.out.println(getAddressResolution(address));
    24. // {province=湖南省, city=长沙市, county=岳麓区, town=, village=永青路668号}
    25. }

    Matcher、MatchResult、Pattern 现在新增了 namedGroups() 相关方法, getAddressResolution() 方法简化成这样了:

    1. public static Map getAddressResolution(String address) {
    2. Matcher matcher = PATTERN.matcher(address);
    3. Map row = new HashMap<>();
    4. if (matcher.matches()) {
    5. Map groupMap = matcher.namedGroups();
    6. groupMap.forEach((key, group) -> row.put(key, matcher.group(group)));
    7. }
    8. return row;
    9. }

    七、集合

    Collections 框架中添加了 SequencedCollection、SequencedSet 和 SequencedMap 三个接口(Java21 新增)。

    1. interface SequencedCollection extends Collection {
    2. // new method
    3. SequencedCollection reversed();
    4. // methods promoted from Deque
    5. void addFirst(E);
    6. void addLast(E);
    7. E getFirst();
    8. E getLast();
    9. E removeFirst();
    10. E removeLast();
    11. }
    12. interface SequencedSet extends Set, SequencedCollection {
    13. SequencedSet reversed(); // covariant override
    14. }
    15. interface SequencedMap extends Map {
    16. // new methods
    17. SequencedMap reversed();
    18. SequencedSet sequencedKeySet();
    19. SequencedCollection sequencedValues();
    20. SequencedSet> sequencedEntrySet();
    21. V putFirst(K, V);
    22. V putLast(K, V);
    23. // methods promoted from NavigableMap
    24. Entry firstEntry();
    25. Entry lastEntry();
    26. Entry pollFirstEntry();
    27. Entry pollLastEntry();
    28. }

    添加这 3 个新接口后,Java 集合类图发生了变化,图示:

    除了这些,现在还可以使用多个工厂方法创建具有给定初始容量的不同类型的 Map(Java19新增)。

    1. HashMap.newHashMap(100);
    2. HashSet.newHashSet(100);
    3. LinkedHashMap.newLinkedHashMap(100);
    4. LinkedHashSet.newLinkedHashSet(100);
    5. WeakHashMap.newWeakHashMap(100);

     Map 创建看起来很简单,但实际上却有一些技巧。例如,HashMap 内部是基于数组构建的,当该数组装满时,它会被复制到一个更大的数组中。所以阿里《JAVA开发手册》也建议设置 HashMap 的初始容量。问题在于,实际上并不仅仅是复制,第一个数组的所有键值对都需要重新计算哈希值,以便放置在新数组的正确位置上。由于哈希值的计算取决于数组的大小,每个数组的存储位置很可能不同。因此,我们不能简单地将第一个数组的内容复制到第二个数组中。为了避免冲突,当数组达到 75% 的容量时,就被认为已经满了。因此,要创建一个可以存储 100 个键值对的 Map,实际上需要一个大小为 134 的数组。考虑到数组的大小必须是 2 的次方,因此实际上会创建一个大小为 256 的数组。这种计算很容易出错,所以现在有了一个工厂方法。现在我们只需要调用 newHashMap(size),传递所需的容量就好了。

    八、日期和时间 API(Java19新增)

    Date and Time API 的一个很好的增加功能是 DateTimeFormatter 的本地化支持ofLocalizedPattern() 工厂方法,传递一个字符串格式,它会生成一个本地化的模式。

    DateTimeFormatterBuilder 也已更新,添加了一个 appendLocalized() 方法,用于添加一个本地化模式(类型为字符串)。

    1. LocalDateTime now = LocalDateTime.now();
    2. DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedPattern("yM");
    3. System.out.println(now.format(formatter)); // 2023年9月

    九、IO流

    PrintStream 在 Java18 中新增了 charset()方法用于获取使用的字符集。

    public Charset charset();

    HttpClient、ExecutorService 和 ForkJoinPool 类在 17 和 21 之间实现了 AutoCloseable。现在可以使用 try-with-resources语句来创建实例。

    十、Math 和 BigInteger

    Math 类和 BigInteger 类也得到了一些关注。首先,Math类添加了一系列方法。

    1. // 执行两个数字的向上取整除法运算,并返回大于或等于除法结果的最小整数。
    2. public static int ceilDiv(int x, int y);
    3. public static long ceilDiv(long x, int y);
    4. public static long ceilDiv(long x, long y);
    5. // 执行两个数字的向上取整除法运算,但是在被除数不能被除数整除时,
    6. // 会抛出ArithmeticException异常。
    7. public static int ceilDivExact(int x, int y);
    8. public static long ceilDivExact(long x, long y);
    9. // 这个方法返回的是两个数字进行向上取整除法运算后的余数。
    10. public static int ceilMod(int x, int y);
    11. public static int ceilMod(long x, int y);
    12. public static long ceilMod(long x, long y);
    13. // 这个方法用于对两个数字进行整除运算,并确保结果是一个整数。
    14. // 如果除数无法整除被除数,将会抛出ArithmeticException异常。
    15. public static int divideExact(int x, int y);
    16. public static long divideExact(long x, long y);
    17. // 执行两个数字的向下取整除法运算,但是在被除数不能被除数整除时,
    18. // 会抛出ArithmeticException异常。
    19. public static int floorDivExact(int x, int y);
    20. public static long floorDivExact(long x, long y);

    添加了 clamp() 方法可以处理 int、long、float 和 double 原始类型,将提供的值限制在给定的最小值和最大值之间。

    1. public static int clamp(long value, int min, int max);
    2. public static long clamp(long value, long min, long max);
    3. public static double clamp(double value, double min, double max);
    4. public static float clamp(float value, float min, float max);

     还有一个方法:unsignedMultiplyHigh(),用于将两个长整型数作为无符号数相乘,并将64位高位作为长整型返回。

    1. public static long unsignedMultiplyHigh(long x, long y);

    BigInteger 类增加了一个功能:在并行中执行乘法运算,使用了 Fork/Join 框架。

    public BigInteger parallelMultiply(BigInteger val);

    十一、Thread

    关于 VirtualThread 的内容这里不做过多介绍,想必各位会在各种途径看到各式各样的文章。在这里,我只想介绍两个方面。

    首先,Thread 现在添加了 join()方法和 sleep()方法,两者都接受 Duration 作为参数,Duration 语义化更加易用。另外就是 isVirtual()方法,用于判断线程是否为虚拟线程。

    1. public static void sleep(Duration duration) throws InterruptedException;
    2. public final boolean join(Duration duration) throws InterruptedException;
    3. public final boolean isVirtual();

    另外需要重点介绍的一个是在 Future 接口中添加的新方法。实际上有三个方法:

    resultNow()exceptionNow() 这两个方法不会抛出已检查异常,因此代码中不再需要 try catch,使用起来更加方便。但请注意,如果调用这些方法并且使用的 Future 对象尚未完成,那么将会得到一个 IllegalStateException异常。需要在确保 Future 对象产生了结果或异常时调用这些方法。

    第三个方法是 state(),可以调用它来检查 Future 对象的当前状态。返回值是一个新的枚举:Future.State。

    1. enum State {
    2. /**
    3. * 表示任务尚未完成
    4. */
    5. RUNNING,
    6. /**
    7. * 表示任务成功完成
    8. */
    9. SUCCESS,
    10. /**
    11. * 表示任务完成但出现异常
    12. */
    13. FAILED,
    14. /**
    15. * 表示任务被取消。
    16. */
    17. CANCELLED
    18. }

    因此,通过这个API,现在可以更精确地监控任务的进展情况。

  • 相关阅读:
    无胁科技-TVD每日漏洞情报-2022-9-19
    【MHA】MySQL高可用MHA介绍7-常见问题
    如何清理 mac 磁盘?快速清理小妙招在这里
    你的哪些骚操作会导致Segmentation Fault😂
    【qt】Qt Creator 设计界面与结果不一致问题
    如何开发通过蓝牙技术实现灯光智能调节的小程序
    tomcat部署
    dom——操作文档树及其案例
    无涯教程-Android - List View函数
    TypeScript学习一(基础类型)
  • 原文地址:https://blog.csdn.net/LU58542226/article/details/133041274