你可能未曾使用的新 Java 特性

开发 后端
Java 是在过去 20 年中一直在市场流行的编程语言。但是最近几年各种替代 Java 的声音不断。

[[353173]]

 Java 是在过去 20 年中一直在市场流行的编程语言。

但是最近几年各种替代 Java 的声音不断。

与 Python,Kotlin,Swift 等现代编程语言相比,开发人员抱怨 Java 过时的编程语法。

但是很多人不知道的是,Java 新版做了很多改进,并为开发人员提供了更有效的方式来编写代码。

如果您想用 Java 更轻松编写简洁和优雅的代码,可以参考以下一些建议,这些语法在 JDK 14 已经提供。

1 Try-with-resource 语句

使用 try-catch 块处理异常,通常需要通过 finally 块来添加清除代码。现在使用 try with resource 语法,开发人员就不用自己操心资源释放。

我们可以在 try 括号内添加资源,以便在 try-catch 块执行后关闭或清理该资源

旧语法

Scanner scanner = null
try { 
    scanner = new Scanner(new File("foo.txt")); 
    while (scanner.hasNext()) { 
        System.out.println(scanner.nextLine()); 
    } 
} catch (FileNotFoundException e) { 
    e.printStackTrace(); 
} finally { 
    if (scanner != null) scanner.close(); 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

新语法

try (Scanner scanner = new Scanner(new File("foo.txt"))) { 
    while (scanner.hasNext()) { 
        System.out.println(scanner.nextLine()); 
    } 
} catch (FileNotFoundException e) { 
    e.printStackTrace(); 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

这将大大减少关闭流或数据库连接的代码行,并减少由于忘记关闭流/连接而导致各种错误的问题。

2 switch 表达式

开发人员经常遇到需要从条件块返回值的情况,但是旧的语法不好解决。

旧语法

private String getUserRole(User user){ 
    String userRole = ""
 
    switch(user.getRole()){ 
        case 0: 
            userRole = "Customer"
            break; 
 
        case 1: 
            userRole = "Editor"
            break; 
 
        case 2: 
            userRole = "Admin"
            break; 
 
        default: throw new IllegalStateException("Unexpected value: " + user.getRole()); 
    } 
    return userRole; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.

就像 Swift 这些现代语言一样,Java 12 引入了 switch 表达式,你可以根据条件返回值。

新语法

private String getUserRoleV2(User user){ 
 
    return switch(user.getRole()){ 
        case 0 -> "Customer"
        case 1 -> "Editor"
        case 2 : 
            // for multi line expression use 'yield' keyword 
            user.setRights(AuthRights.absolute); 
            yield "Admin"
        default -> throw new IllegalStateException("Unexpected value: " + user.getRole()); 
    }; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

这大大减少了项目中的 LOC(代码行),并使修改相对容易。

3 用 var 初始化

Java 本质上是严格类型的语言,使用严格类型定义是开发人员偏好的问题。但是支持类型推断可以降低代码复杂性,Java 10 增加了对局部变量的类型推断的支持。

private void init(){ 
    var str = "Java 10"; // infers String 
    var list = new ArrayList<String>();  
    var stream = list.stream(); // infers Stream<String> 
 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

但 Java 仍然是一种静态类型的语言,仅在有足够的信息可用于初始化时才推断类型。因此如果变量满足以下条件,则使用 var 初始化是合法的:

  • 它只能是局部变量(类成员或函数参数不支持)
  • 声明后应立即定义(define)

4 记录 (record)

使用 Java 最常见的抱怨之一,需要编写大量代码来使类可用,例如一堆 toString 或 equals 定义,因此代码看起来很冗长。Java 14 提供了 Record 语法,使类型声明更加简洁,当我们需要在一个类名下绑定多个值时,它非常有用。

这是 Oracle 网站上的一篇文章示例,展示了使用记录的优势

var order = new FXOrderClassic(1,  
        CurrencyPair.GBPUSD, 
        Side.Bid, 1.25,  
        LocalDateTime.now(),  
        1000); 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

像这样的标准对象的调用,需要定义类型 FXOrderClassic。

旧语法

public final class FXOrderClassic { 
    private final int units; 
    private final CurrencyPair pair; 
    private final Side side; 
    private final double price; 
    private final LocalDateTime sentAt; 
    private final int ttl; 
 
    public FXOrderClassic(int units, 
                          CurrencyPair pair, 
                          Side side, 
                          double price, 
                          LocalDateTime sentAt, 
                          int ttl) { 
        this.units = units; 
        this.pair = pair; // CurrencyPair is a simple enum 
        this.side = side; // Side is a simple enum 
        this.price = price; 
        this.sentAt = sentAt; 
        this.ttl = ttl; 
    } 
 
    public int units() { 
        return units; 
    } 
 
    public CurrencyPair pair() { 
        return pair; 
    } 
 
    public Side side() { 
        return side; 
    } 
 
    public double price() { return price; } 
 
    public LocalDateTime sentAt() { 
        return sentAt; 
    } 
 
    public int ttl() { 
        return ttl; 
    } 
 
    @Override 
    public boolean equals(Object o) { 
        if (this == o) return true
        if (o == null || getClass() != o.getClass()) 
            return false
 
        FXOrderClassic that = (FXOrderClassic) o; 
 
        if (units != that.units) return false
        if (Double.compare(that.price, price) != 0) 
            return false
        if (ttl != that.ttl) return false
        if (pair != that.pair) return false
        if (side != that.side) return false
        return sentAt != null ? 
                sentAt.equals(that.sentAt) : that.sentAt == null
    } 
 
    @Override 
    public int hashCode() { 
        int result; 
        long temp
        result = units; 
        result = 31 * result + 
                (pair != null ? pair.hashCode() : 0); 
        result = 31 * result + 
                (side != null ? side.hashCode() : 0); 
        temp = Double.doubleToLongBits(price); 
        result = 31 * result + 
                (int) (temp ^ (temp >>> 32)); 
        result = 31 * result + 
                (sentAt != null ? sentAt.hashCode() : 0); 
        result = 31 * result + ttl; 
        return result; 
    } 
 
    @Override 
    public String toString() { 
        return "FXOrderClassic{" + 
                "units=" + units + 
                ", pair=" + pair + 
                ", side=" + side + 
                ", price=" + price + 
                ", sentAt=" + sentAt + 
                ", ttl=" + ttl + 
                '}'
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.

新语法

public record FXOrder(int units, 
                      CurrencyPair pair, 
                      Side side, 
                      double price, 
                      LocalDateTime sentAt, 
                      int ttl) {} 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

5 增强的 instance of

Java 14 引入了 instanceof 模式匹配的功能,这意味着在使用 instanceof 的实例类型检查时,不再需要显式的类型转换。

旧语法

private Entries getEntries(User user){ 
    if (user instanceof Editor) { 
        Editor editor = (Editor) user
 
        // use editor specific methods 
        var entries = editor.getEntries(); 
        return entries; 
    } 
     
    return null

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

新语法

private Entries getEntries(User user){ 
     
    if (user instanceof Editor editor) { 
        // use group specific methods 
        var entries = editor.getEntries(); 
        return entries; 
    } 
 
    return null

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

6 文本块

支持文本块并不是什么新鲜事,但在 Java 中却是工程师期待已久的功能。Java 开发人员总是渴望以更简单的方式打印多行字符串文字,而不使用讨厌的串联。Java 新版支持多行字符串文字。

旧语法

String html = "<HTML>" + 
"\n\t" + "<BODY>" + 
"\n\t\t" + "<H2>\"Hurray! Java 14 is here\"</H2>" + 
"\n\t" + "</BODY>" + 
"\n" + "</HTML>"
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

使用三引号 ,就可以使用此功能,该功能在使用结构化字符串时非常方便,例如以一定的对齐方式和间距编写文件或添加多行 html 块

新语法

String html = ""
<HTML> 
  <BODY> 
    <H2>"Hurray! Java 14 is here"</H2> 
  </BODY> 
</HTML> 
"""; 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

7 有意义的 NPE (空指针)消息

空指针异常(NPE)一直是 Java 开发人员的噩梦,并且是开发人员遇到的最常见的问题。

但是 NPE 消息常常不能提供有关该问题的足够信息。

var task = new Task(); 
final boolean isDataConsumed = task.getData().getBucket().isConsumed; 
  • 1.
  • 2.

在代码段中,可能存在多个故障点,例如

  • getData()返回一个空值
  • getBucket()返回一个空值

但以下 NPE 报错未提供有关该问题的足够详细信息。

为了解决此问题,Oracle 添加 JEP 358,提供有用的 NullPointExceptions

NullPointerException 通过精确描述哪个变量来提高 JVM 生成错误信息的可用性。

你可以通过在 Java 命令中添加以下标志来使用此功能

-XX:+ShowCodeDetailsInExceptionMessages

使用该标志,JVM 将提供更多有意义的信息,以便跟踪确切的故障点

英文原文:

https://medium.com/swlh/working-with-new-generation-of-java-236e2dc38316

本文转载自微信公众号「高可用架构」,可以通过以下二维码关注。转载本文请联系高可用架构公众号。

 

责任编辑:武晓燕 来源: 高可用架构
相关推荐

2019-11-05 16:51:41

JavaScript数据es8

2019-03-04 09:39:41

Java开发代码

2025-01-30 00:00:00

API指令集计算能力

2013-10-21 17:57:54

2012-03-24 21:02:41

iOS

2022-01-17 22:33:37

Java特定类型

2015-06-29 09:40:10

Rails新特性

2014-08-21 10:34:11

Java 9Java

2021-02-22 11:51:15

Java开发代码

2024-11-19 10:26:35

2014-07-15 14:48:26

Java8

2020-09-17 13:10:54

Java1编程语言新特性

2017-11-22 09:57:22

HTML5存储代码

2011-12-14 16:15:17

MySQL

2022-03-09 08:14:24

CSS容器container

2021-10-12 07:15:03

C++20特性

2020-04-26 10:52:37

LinuxUbuntu 20.0Ubuntu 18.0

2015-08-28 09:43:49

Java 8新特性处理集合

2020-11-16 12:09:25

Python开发工具

2024-11-08 08:34:59

RocketMQ5.Remoting通信
点赞
收藏

51CTO技术栈公众号