JDK17好用吗?

前言

JDK的版本迭代速度确实迅猛,如今已迈入JDK26的时代。尽管版本众多,JDK8依然以其广泛的应用基础,成为众多开发者心中的经典,正如俗语所言:“他发任他发,我用Java8”。

然而,我对于升级JDK版本的态度曾一度犹豫,认为投入与回报不成正比。直到某次,我偶然间接触到一些采用JDK17新特性编写的代码,这些新语法着实让我眼前一亮,激发了我对升级JDK的兴趣。它们不仅提升了代码的简洁性与效率,更让我对Java的未来充满了期待。

DK17语法新特性

这个新特性的实用性极强。在引入这个特性之前,编写长文本的过程繁琐且枯燥。即使有IDEA等集成开发环境的自动处理,但最终的效果仍然不尽如人意,拼接符号的存在使得代码显得凌乱。然而现在,通过新引入的字符串块功能,我们能够轻松地编写JSON、HTML、SQL等长文本,呈现出的代码更为简洁优美。我强烈推荐这个特性,它值得五星好评。因为它让我们在编写长文本时,可以更专注于字符串内容本身,而非繁琐的拼接操作。

原来的写法 

/**
 * 使用JDK15以上版本返回HTML文本
 *
 * @return 返回HTML文本
 */
public static final String getHtmlJDK15() {
    return """
        <html>
            <body>
                <p>Hello, world</p>
            </body>
        </html>
        """;
}

 新的写法

/**
 * 使用JDK17返回HTML文本
 * @return 返回HTML文本
 */
public static final String getHtmlJDK17() {
    return """
        <html>
            <body>
                <p>Hello, world</p>
            </body>
        </html>
        """;
}

NullPointerException增强

这个新功能无疑是强大且实用的,我相信每个Java开发者对此都充满了期待。空指针异常(NPE)一直是我们Java开发者的困扰,原因在于当对象为空时,错误信息并不能直观地指出具体哪个对象为空。相反,系统只会抛出一个NullPointerException以及一堆难以理解的堆栈信息,这使得问题的定位变得耗时而复杂。特别是当遇到喜欢级联调用的代码时,逐行排查就更加棘手。

如果在测试环境中,我们可能还需要通过远程调试来查明空对象,这无疑是一项耗时且劳累的工作。为了应对这个问题,阿里的编码规范甚至规定不允许级联调用,但这并不能从根本上解决问题。

然而,Java17终于在这个问题上取得了突破,它提供了更详细的空指针异常信息,使开发者能够更快速地定位到问题的源头。这无疑是对我们开发者的一大福音。

实现代码 

public static void main(String[] args) {
    try {
        //简单的空指针
        String str = null;
        str.length();
    } catch (Exception e) {
        e.printStackTrace();
    }
    try {
        //复杂一点的空指针
        var arr = List.of(null);
        String str = (String)arr.get(0);
        str.length();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Records

在Java编程中,POJO对象(如DO、PO、VO、DTO等)通常包含一系列的成员变量及其对应的Getter和Setter方法。虽然我们可以通过工具或IDE自动生成这些代码,但其修改和维护工作还是相当繁琐。为解决这一问题,Lombok插件应运而生,它能够在编译期间自动生成Getter、Setter、hashcode、equals和构造函数等代码,使用起来非常便捷。然而,使用Lombok插件的前提是团队所有成员都需要安装和理解该插件。

针对这种情况,Java引入了一种标准的解决方案:Records。它通过简洁的语法定义数据类,极大地简化了POJO类的编写过程。以下是一个示例:

虽然hashcode和equals方法仍需我们手动编写,但现代IDE能够帮助我们自动生成这些方法。这个新特性有效地解决了模板代码的问题,使我们的代码更加简洁,提高了代码的可维护性。

 

/**
 * 3星
 *
 * @param stuId     学生ID
 * @param stuName   学生名称
 * @param stuAge    学生年龄
 * @param stuGender 学生性别
 * @param stuEmail  学生邮箱
 */
public record StudentRecord(Long stuId,
                            String stuName,
                            int stuAge,
                            String stuGender,
                            String stuEmail) {
    public StudentRecord {
        System.out.println("构造函数");
    }

    public static void main(String[] args) {
        StudentRecord record = new StudentRecord(1L, "张三", 16, "男", "xxx@qq.com");
        System.out.println(record);
    }
}

全新的switch表达式

有些人可能会问,Java语言不是早就支持了switch语句吗,这次有什么特别的变化需要讨论?实际上,这次的更新确实值得我们深入探讨一番。

在Java12版本中,Java引入了switch表达式,这里需要注意的是,新引入的是表达式,而非语句,这与我们之前常用的switch有所不同。如果你对表达式和语句之间的差别不太明确,我建议你先去了解一下。最主要的差别就是表达式有返回值,而语句没有。

此外,Java还引入了模式匹配,以及yield关键字和“->”运算符。这些新特性使得全新的switch表达式在使用上变得更加便捷和高效。这些变化,无疑使得编程体验有了飞跃式的提升。

package com.xttblog.jdk17;

public class SwitchDemo {
    /**
     * 在JDK8中获取switch返回值方式
     *
     * @param week
     * @return
     */
    public int getByJDK8(Week week) {
        int i = 0;
        switch (week) {
            case MONDAY, TUESDAY:
                i = 1;
                break;
            case WEDNESDAY:
                i = 3;
                break;
            case THURSDAY:
                i = 4;
                break;
            case FRIDAY:
                i = 5;
                break;
            case SATURDAY:
                i = 6;
                break;
            case SUNDAY:
                i = 7;
                break;
            default:
                i = 0;
                break;
        }

        return i;
    }

    /**
     * 在JDK17中获取switch返回值
     *
     * @param week
     * @return
     */
    public int getByJDK17(Week week) {
        // 1, 现在的switch变成了表达式,可以返回值了,而且支持yield和->符号来返回值
        // 2, 再也不用担心漏写了break,而导致出问题了
        // 3, case后面支持写多个条件
        return switch (week) {
            case null -> -1;
            case MONDAY -> 1;
            case TUESDAY -> 2;
            case WEDNESDAY -> 3;
            case THURSDAY -> {yield 4;}
            case FRIDAY -> 5;
            case SATURDAY, SUNDAY -> 6;
            default -> 0;
        };
    }

    private enum Week {
        MONDAY,
        TUESDAY,
        WEDNESDAY,
        THURSDAY,
        FRIDAY,
        SATURDAY,
        SUNDAY
    }
}

 私有接口方法

自从Java8开始,我们可以在interface中添加默认方法。然而,这引发了一个问题,如果默认方法的代码体过大,我们应该如何处理?是否应该将其拆分并移至另一个类中编写?这似乎并不是一个很合理的解决办法。

为了解决这个问题,Java17引入了一个新的特性:接口私有方法。如果一个默认方法的代码体过大,我们现在可以通过新增接口私有方法来进行合理的代码拆分,这确实是一个值得赞赏的改进。这一特性既解决了代码冗余的问题,也保持了代码的清晰和高内聚。

 

public interface PrivateInterfaceMethod {
    /**
     * 接口默认方法
     */
    default void defaultMethod() {
        privateMethod();
    }

    // 接口私有方法,在Java8里面是不被允许的,不信你试试
    private void privateMethod() {
    }
}

模式匹配

在JDK 17中,模式匹配主要被应用于instanceof表达式,这一特性极大地增强了instanceof的语法和功能,使得类型检查和类型转换变得更加简洁和高效。

在早期的Java版本中,我们通常需要结合使用instanceof和类型转换来判断对象的类型并进行相应的处理,这样的做法往往会导致代码冗长且难以阅读。而现在,通过模式匹配,我们可以直接在instanceof表达式中进行类型检查和类型转换,从而避免了繁琐的类型转换步骤,使得代码更加简洁、清晰,同时也提高了代码的可读性和可维护性。

原来的写法 

/**
 * 旧式写法
 *
 * @param value
 */
public void matchByJDK8(Object value) {
    if (value instanceof String) {
        String v = (String)value;
        System.out.println("遇到一个String类型" + v.toUpperCase());
    } else if (value instanceof Integer) {
        Integer v = (Integer)value;
    System.out.println("遇到一个整型类型" + v.longValue());
    }
}

现写法

/**
 * 转换并申请了一个新的变量,极大地方便了代码的编写
 *
 * @param value
 */
public void matchByJDK17(Object value) {
    if (value instanceof String v) {
        System.out.println("遇到一个String类型" + v.toUpperCase());
    } else if (value instanceof Integer v) {
        System.out.println("遇到一个整型类型" + v.longValue());
    }
}

集合类的工厂方法

在Java8的时代,即便创建一个很小的集合,或者固定元素的集合,过程也相对繁琐。例如,如果我们想要创建一个包含几个固定元素的集合,我们通常需要编写一些样板代码来实例化集合,然后逐个添加元素。这种做法不仅代码冗长,而且容易出错,尤其是在需要频繁创建小集合的场景下,这种繁琐的操作会大大降低开发效率。

为了简化这一过程,一些开发者甚至会选择引入第三方库,如Guava,它提供了一些方便的工具方法来创建集合,使得代码更加简洁。例如,Guava的ImmutableList.of()方法可以快速创建一个不可变的列表,而无需手动添加每个元素。

然而,引入第三方库也带来了一些问题,比如增加了项目的依赖管理复杂性,可能会引入不必要的依赖,以及可能的兼容性问题。因此,虽然第三方库在一定程度上简化了集合的创建,但它并不是一个完美的解决方案。

幸运的是,随着Java语言的不断发展,后续版本中引入了更简洁的集合创建方式,如Java9中的List.of()、Set.of()和Map.of()方法,这些方法允许我们以更简洁的方式创建不可变集合,大大减少了样板代码,提高了开发效率。

 原来的写法

Set<String> set = new HashSet<>();
set.add("a");
set.add("b");
set.add("c");

新的写法

Set<String> set = Set.of("a", "b", "c");

其他的新特性

  新的String方法

Java引入了一系列的新的字符串操作方法,以下是各个方法的详细概述:

1. `repeat(int n)`:这个方法可以生成重复的字符串。它接收一个整数n作为参数,然后返回一个新字符串,这个新字符串由原字符串的内容重复n次组成。

2. `isBlank()`:这个方法用于检查字符串是否为空或者只包含空白字符。这是一个很有用的方法,因为在此之前,开发者通常需要引入第三方库才能方便地实现这个功能。

3. `strip()`:这个方法用于去除字符串两边的空格。这个方法的功能比trim()要强大,因为它支持全角和半角空格,而trim()只支持半角空格。

4. `lines()`:这个方法能根据字符串中的行终止符(如"\n","\r","\r\n")提取出行为单位的流。这个方法返回一个由行组成的Stream,让我们可以方便地对每一行的内容进行处理。

5. `indent(int n)`:这个方法用于给字符串做缩进。它接收一个整数n作为参数,如果n为正,表示向右缩进n个空格,如果n为负,表示删除左侧的n个空格。

6. `transform(Function<? super String, ? extends R> function)`:这个方法接受一个函数作为参数,用于实现字符串的转换。这个函数接收一个字符串,并返回一个转换后的结果。我们可以使用这个方法来进行复杂的字符串转换,如大小写转换,删除特定字符等。

全新的HttpClient 

这个API首次出现在Java 9中,但那时是一个实验性的功能,在Java 11中它被正式发布并成为稳定的API,所以在Java 17中你可以放心地使用它。

在这个API出现之前,JDK自带的HTTP客户端功能相对较弱,使用也比较复杂,这使得很多开发者不愿意使用它。相反,他们更倾向于使用像OkHttp、RestTemplate、Apache的HttpClient和Feign这样的第三方库,因为这些库提供的API更加友好,功能也更加强大。

然而,新的HTTP客户端API在设计时就考虑到了这些问题,它采用了Fluent API的设计风格,让我们可以以链式调用的方式来发送HTTP请求,这大大提高了代码的可读性和易用性。此外,新的API还支持HTTP/2和WebSocket,使得我们可以以更高效和现代的方式来进行网络通信。

例如,我们可以如下所示地发送一个GET请求:

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
      .uri(URI.create("http://example.com/"))
      .build();

client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
      .thenApply(HttpResponse::body)
      .thenAccept(System.out::println);

这段代码首先创建了一个HttpClient对象,然后创建了一个HttpRequest对象,并设置了请求的URI。然后,我们发送了这个异步的请求,并且注册了一个回调函数,当得到响应时,这个函数会输出响应的内容。

这就是新的HTTP客户端API,它让我们可以更方便地发送HTTP请求,而不需要依赖任何第三方库,确实让人感觉非常清爽。

小结一下

作为程序员,持续学习和适应新技术是职业发展的关键。随着Java 8的官方免费支持即将结束,许多项目正在转向更新的Java版本,特别是Java 17。例如,广受欢迎的Spring Boot框架在2022年1月20日发布了基于Java 17的3.0版本的第一个里程碑版本(M1)。这一转变意味着Spring Boot项目所依赖的所有组件也将随之升级,以支持Java 17的新特性。

如果你希望利用Java 17中的新特性,那么在Java 8环境下编写的代码将无法通过编译。因此,及时更新你的技术栈,学习Java 17的新特性,对于保持项目的现代化和竞争力至关重要。拖延到最后一刻再进行转换可能会导致项目面临技术债务和兼容性问题,从而影响开发进度和产品质量。

总结来说,随着Java 8支持的结束和Spring Boot 3.0的发布,现在是时候开始学习Java 17并将其应用到你的项目中了。这样做不仅可以让你利用最新的语言特性,还可以确保你的项目能够跟上技术发展的步伐,避免未来可能出现的技术障碍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值