有时候,如果你是一直编写Java程序,从未去写过其它语言的话,你可能压根意识不到Java之中有些原来写法其实是很啰嗦的。而当你使用其它一些语言的更简洁的特性时,可能就会有一种:”哇,原来可以这样"的认知。
而在这其中,模式匹配Pattern Matching就是这么一个点。
这周,继续聊一聊Java 8之后的新特性,这次聊一聊模式匹配这个特性。
这是Java 8之后的那些新特性系列的第八篇。这个系列的其它文章为:
- 1. Java 8之后的那些新特性(一):局部变量var
- 2. Java 8之后的那些新特性(二):文本块 Text Blocks
- 3. Java 8之后的那些新特性(三):Java System Logger
- 4. Java 8之后的那些新特性(四):网络请求 Java Http Client
- 5. Java 8之后的那些新特性(五):Helpful NullPointerExceptions
- 6. Java 8之后的那些新特性(六):记录类 Record Class
- 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是怎么处理这个点的。
代码语言:javascript复制Kotlin
@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也是类似的
代码语言:javascript复制TypeScript
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)以了解我在维护的全栈式领域驱动开源框架。