前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自 java8 以来开发者友好的新特性

自 java8 以来开发者友好的新特性

作者头像
用户3147702
发布2022-12-21 17:57:10
2910
发布2022-12-21 17:57:10
举报
文章被收录于专栏:小脑斧科技博客

1. 引言

此前,在 java8 问世时,我写过一篇文章,详细介绍了 java8 的新特性。

如今,java8 已经问世 8 年多了,java 已经更新到了 java19 版本,尽管目前国内 java8 仍然占据着最大的使用比例。但这不妨碍我们来看看,8 年来,java 在使用上的体验出现了哪些优化。

本文,我们就来一一看看自 java8 以来,有哪些开发者友好的新特性诞生吧。

2. switch 语句的变化

2.1 switch 表达式

switch 语句有时显得比较复杂:

代码语言:javascript
复制
 public String oldMultiSwitch(int day) {
    switch (day) {
       case 1:
       case 2:
       case 3:
       case 4:
       case 5:
          return "workday";
       case 6:
       case 7:
          return "weekend";
       default:
          return "invalid";
    }
 }

java12 对此进行了优化:

代码语言:javascript
复制
 public String newMultiSwitch(int day) {
    return switch (day) {
       case 1, 2, 3, 4, 5 -> "workday";
       case 6, 7 -> "weekend";
       default -> "invalid";
    };
 }

通过箭头让 switch 语句变成了一个表达式,十分简洁明了。

2.2 switch 的类型匹配

自 java17 开始,可以将类型的判断应用到 switch 表达式中了:

代码语言:javascript
复制
 public String newSwitchWithPatternMatching(Pet pet) {
    return switch (pet) {
       case Cat c -> "cat";
       case Dog d -> "dog";
       default -> "other pet";
    };
 }

pet 变量被声明为抽象类 Pet 的对象,这个方法则实现了根据 pet 具体实现类的不同返回不同的字符串。

3. 密封类 Sealed Classes

密封类是 Kotlin 中的一个特性,在 java17 中也开始了对这一特性的支持。

Java17 引入一对新的关键词:sealed 与 non-sealed 以及与之配套使用的 permits 关键字。

3.1 密封父类

有时,在我们设计一个类时,我们只希望这个类派生出一部分我们自己定义的类,而不想让其他人去派生这个类,此时,我们就可以使用 sealed class 这个新特性:

代码语言:javascript
复制
 public abstract sealed class Pet permits Cat, Dog {}

这意味着,对于 Pet 这个类,我们只允许派生出 Cat 和 Dog 两个类,我们不允许其他类直接派生自 Pet 类。

所以,在我们定义 sealed 类的子类时,我们必须要加上 final 关键字,防止从这些子类派生:

代码语言:javascript
复制
 public final class Cat extends Pet {}

3.2 在子类上解除密封

如果我们只是不想让任何类直接派生自 Pet 类,但却允许让 Cat 和 Dog 拥有各自的子类,那么,我们就可以使用 non-sealed 关键字来解开限制:

代码语言:javascript
复制
 public non-sealed class Dog extends Pet {}

4. 文本块

在 python 等语言中,拥有文本块的特性:

代码语言:javascript
复制
 def getNewPrettyPrintJson():
     return """
 {
     "firstName": "Piotr",
     "lastName": "Mińkowski"
 }
 """

但是这段代码在 java 中写起来就较为复杂:

代码语言:javascript
复制
 public String getOldPrettyPrintJson() {
    return "{\n" +
           "     \"firstName\": \"Piotr\",\n" +
           "     \"lastName\": \"Mińkowski\"\n" +
           "}";
 }

从 java13 开始,java 也支持了文本块的特性:

代码语言:javascript
复制
 public String getNewPrettyPrintJson() {
    return """
           {
              "firstName": "Piotr",
              "lastName": "Mińkowski"
           }
           """;
 }

5. Optional 类增加了新方法

Optional 类作为 java8 的新特性,对于预防代码中令人头疼的可能的空指针异常有着非常好的作用。

在 java9 和 java10 中,相继为 Optional 类增加了新的实用的方法:

  1. orElseThrow:不存在则抛出 NoSuchElementException;
  2. ifPresentOrElse:指定不存在的行为。

有了这两个方法,原本复杂的 if 判断就可以简化成一个简单的语句了:

代码语言:javascript
复制
 public Person getPersonByIdOldWay(Long id) {
    Optional<Person> personOpt = repository.findById(id);
    if (personOpt.isPresent())
       return personOpt.get();
    else
       throw new NoSuchElementException();
 }
 
 public void printPersonById(Long id) {
    Optional<Person> personOpt = repository.findById(id);
    personOpt.ifPresentOrElse(
       System.out::println,
       () -> System.out.println("Person not found")
    );
 }

6. 集合工厂方法

Java9 开始,List 和 Map 都支持了 of 方法,用来简单的生成不可变的集合对象,尽管这个特性在 guava 的 ImmutableMap、ImmutableList 中早已支持:

代码语言:javascript
复制
 List<String> fruits = List.of("apple", "banana", "orange");
 Map<Integer, String> numbers = Map.of(1, "one", 2,"two", 3, "three");

当然,这样生成的集合是不可变集合,这意味着,我们不能扩充集合的容量,如果想方便的生成可变的 List,还是推荐:

代码语言:javascript
复制
 public List<String> fruitsFromArray() {
    String[] fruitsArray = {"apple", "banana", "orange"};
    return Arrays.asList(fruitsArray);
 }

7. 记录类 record class

对于一个 java 的数据类,我们经常会为它设置 getter 和 setter 方法,以及 toString、equals、hasCode 等方法,这看起来非常繁琐,所以我们往往会使用 Lombok 的 @Data 注解来简化这一过程。

但大部分时候,对于一个数据类,我们通常只需要生成 getter 方法,因为一旦对象创建,我们只需要频繁获取其字段的值,而不需要重新设置。

java14 中,引入了 record 关键字,简化了上述类定义的过程:

代码语言:javascript
复制
 public record Person(String name, int age) {}

这个 record 类型的类声明会等效于为 Person 类添加了 name 和 age 两个字段的 getter 方法,同时也会自动创建 toString、equals、hasCode 等方法,使用起来就非常简单了。

8. 接口的私有方法

在 java8 中,引入了 default 关键字,允许为接口定义方法的默认实现。到了 java9 中,允许为接口定义 private 的方法,这个特性可以说得到了完全的实现:

代码语言:javascript
复制
 public interface ExampleInterface {
    private void printMsg(String methodName) {
       System.out.println("Calling interface");
       System.out.println("Interface method: " + methodName);
    }
 
    default void method1() {
       printMsg("method1");
    }
 
    default void method2() {
       printMsg("method2");
    }
 }

9. 运行时类型的局部变量

自 java10,你可以使用 var 关键字来定义运行时类型的变量,从 java11 开始,var 关键字可以用在 lambda 表达式中了:

代码语言:javascript
复制
 public String sumOfString() {
    BiFunction<String, String, String> func = (var x, var y) -> x + y;
    return func.apply("abc", "efg");
 }

结语

本文介绍了自 java8 以来,对开发者友好的 java 新特性,实际上,除了这些编写代码过程上的便捷与简化,java 在运行上和垃圾回收上的性能提升也十分值得关注,这部分我们就留待后续文章来进行介绍吧。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-11-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小脑斧科技博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 引言
  • 2. switch 语句的变化
    • 2.1 switch 表达式
      • 2.2 switch 的类型匹配
      • 3. 密封类 Sealed Classes
        • 3.1 密封父类
          • 3.2 在子类上解除密封
          • 4. 文本块
          • 5. Optional 类增加了新方法
          • 6. 集合工厂方法
          • 7. 记录类 record class
          • 8. 接口的私有方法
          • 9. 运行时类型的局部变量
          • 结语
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档