Java 8 之后的那些新特性(八):模式匹配 Pattern Matching

2022-06-07 19:14:59 浏览数 (1)

有时候,如果你是一直编写Java程序,从未去写过其它语言的话,你可能压根意识不到Java之中有些原来写法其实是很啰嗦的。而当你使用其它一些语言的更简洁的特性时,可能就会有一种:”哇,原来可以这样"的认知。

而在这其中,模式匹配Pattern Matching就是这么一个点。

这周,继续聊一聊Java 8之后的新特性,这次聊一聊模式匹配这个特性。

这是Java 8之后的那些新特性系列的第八篇。这个系列的其它文章为:

  1. 1. Java 8之后的那些新特性(一):局部变量var
  2. 2. Java 8之后的那些新特性(二):文本块 Text Blocks
  3. 3. Java 8之后的那些新特性(三):Java System Logger
  4. 4. Java 8之后的那些新特性(四):网络请求 Java Http Client
  5. 5. Java 8之后的那些新特性(五):Helpful NullPointerExceptions
  6. 6. Java 8之后的那些新特性(六):记录类 Record Class
  7. 7. Java 8之后的那些新特性(七):switch表达式 Switch Expressions

你熟悉的点

在Java编程中,在判断一个对象是否属于某个具体的子类时,你一定都写过类似的代码。

代码语言:javascript复制
    @Test
    void testNotPatternMatching(){
        AbstractMessage message = randomMessage();
        if(message instanceof TextMessage){
            var textMessage = (TextMessage)message;
            Assertions.assertNotNull(textMessage.getText());
        }
        else if(message instanceof ImageMessage){
            var imageMessage = (ImageMessage)message;
            Assertions.assertNotNull(imageMessage.getData());
        }
    }

这个写法对所有Java程序员都非常熟悉,在遇到类似的场景,比如判定究竟属于哪个子类或实现时,我们都会先用instanceof来判断,然后强制转为一个具体的子类来调用子类的一些方法或属性。

如果你一直编写Java,我相信你从未感觉这个点上有什么问题。我也一直没有意识到,直到我使用了Kotlin与TypeScript之后,在这个点上,它们的处理方式并不是这样。

一对比,我就发现,这个强制转换,其实是非常多余的,完全可以在语言特性级别自动进行转换,省略掉这个多余的强制转换。

Kotlin与TypeScript

我们可以借鉴下Kotlin以及TypeScript是怎么处理这个点的。

Kotlin

代码语言:javascript复制
    @Test
    fun testPatternMatching(){
        val message = randomMessage()
        if(message is TextMessage){
            //message在这里自动转为TextMessage类型了
            Assertions.assertNotNull(message.text)
        }else if(message is ImageMessage){
            //message在这里自动转为ImageMessage类型了
            Assertions.assertNotNull(message.data)
        }
    }

    @Test
    fun testPatternMatchingInWhen(){
        when(val message = randomMessage()){
            is TextMessage -> Assertions.assertNotNull(message.text)
            is ImageMessage -> Assertions.assertNotNull(message.data)
        }
    }

同样,我们看下TypeScript也是类似的

TypeScript

代码语言:javascript复制
test('测试TypeScript的Patter Matching', () => {
    const message:AbstractMessage = randomMesage()
    if(message instanceof TextMesasge){
        //message在这里自动转为TextMessage类型了
        expect(message.text).toBeDefined()
    }
    else if(message instanceof ImageMessage){
        //message在这里自动转为ImageMessage类型了
        expect(message.data).toBeDefined()
    }
})

可以看到,现代的一些新语言,在一些语法点的简洁性上确实比传统的Java好很多,无论是Kotlin还是TypeScript都可以做到模式匹配,并不需要你手动来强制转换一次。

虽然这只是一行代码的问题,但事实上在使用Kotlin类似的一些语言上,类似的简洁的点非常多,所谓积小成多,就是因为这些小的点积累起来,使得Kotlin成为一门better java

Java的改进

不过,这并不意味着Java止步不前,Java虽然历史悠久,但却也从未停止自己前进的步伐。

终于在Java 17的时候,模式匹配Pattern Matching成为了Java中的一个正式的新特性。所以,我们现在使用Pattern Matching来重写这个代码。

代码语言:javascript复制
    @Test
    void testPatternMatching(){
        AbstractMessage message = randomMessage();
        if(message instanceof TextMessage textMessage){
            Assertions.assertNotNull(textMessage.getText());
        }
        else if(message instanceof ImageMessage imageMessage){
            Assertions.assertNotNull(imageMessage.getData());
        }
    }

是不是和别的语言也非常相似了。

不过有一点不同,在Java的Pattern Matching中,它并没有把原变量进行Pattern Matching处理,而是允许你在后面定义一个新变量来做Pattern Matching。

Switch与Patterm Matching

其实,Java的Pattern Matching除了可以在instanceof中使用以外,还可以在另一个场景中,Switch中也能使用。

不过Pattern Matching与Switch的结合,仍然是预览版的新特性,并没有正式确定。

在Java的新特性中,预览版意味着它在这个版本中引入,但期望收到反馈,并在未来的版本优化与改进它。所以,做为我们这样普通的Java程序员,可能并不需要太关注预览版的新特性,因为它很可能在未来会有变更。

所以我在这里就不介绍Pattern Matching与Switch结合的使用了。

但是你可以期待未来的某个Java版,你肯定可以在Switch也使用上这个Pattern Matching了。

END

这就是这周讲的Pattern Matching这个特性,其实这个特性严格的说并不是非常大,你甚至可以认为可有可无。

但从这小微小的改进中,我仍然能感受到已经27岁的Java语言,从未停止自己的脚步,不断的在前进。

这是我们做为Java程序员,应该非常高兴看到的事情了。

下周继续,讲下另一个比较重要的新特性,密封类 Sealed Class

关于我

我是御剑,一个致力于实践与传播编码之道的全栈式程序员。

访问微言码道(https://taoofcoding.tech)以阅读更多我写的文章;

访问myddd(https://myddd.org)以了解我在维护的全栈式领域驱动开源框架。

0 人点赞