为什么每个 Java 开发者都需要了解 Scala

前面我们一起回顾了第九期 Scala & Java Meetup 中最受关注的话题 —— jdk 并发编程的终极解决方案:虚拟线程,探讨了这一新特性对包括 Scala 在内的响应式编程语言的影响。

本次 Meetup 的首位分享者 Chunsen,在加入 Tubi 成为 Scala 开发者之前,曾在 Java 开发领域深耕多年。他分享了从 Java 转向 Scala 的一些体验,以及“回头再写 Java 一定会想念 Scala 的那些点”,也欢迎观看直播回放。

欢迎关注比图科技公众号,了解 Scala 最新资讯及活动。也欢迎你在后台留言,申请加入 Scala 开发交流群!

话题回顾

Java 语言的发展是非常成功的,尤其是在 Web 后台领域。自 1995 年诞生以来,Java 凭借网络服务的兴起,成为了互联网行业最常用的编程语言之一。Java 最初设计为一种面向对象的编程语言,旨在简化跨平台开发,具有可移植性和安全性,比 C++ 更简单易用,因此 Java 的很多特性与 C++ 比较类似。Scala 是一门在 2003 年始源于研究项目,旨在为 JVM 平台提供一种更具表达力和灵活性的编程语言,融合了面向对象和函数式编程的特性。

如果用一句话来总结 Java 和 Scala 的差异,那就是 Scala 作为一个相对于 Java 历史包袱更小的编程语言,可以更多地尝试融合更多现代化的优秀编程思想,进一步简化编程过程;同时,Scala 最初的设计者也在观察到 Java 语言发展过程中相对落后 / 冗余的方面后,借鉴了函数式编程等其他编程语言的优点,形成了编程风格简洁的多范式编程语言。!

Java 开发者非常适合了解学习 Scala 的原因

从宏观上来说,由于 Java 与 Scala 在渊源上的联系,Java 开发者学习 Scala 具有明显的优势。比如 Scala 和 Java 都是运行在 JVM(Java 虚拟机)上的编程语言,两者之间可以互相调用(有时也会存在不容易兼容的情况),并利用包括跨平台和成熟的生态系统在内的 JVM 优势以及 JVM 升级带来的性能提升等。

Scala 和 Java 各自都有很多优秀的库,可以比较容易地互相调用,这意味着 Scala 和 Java 代码可以混合编译,并共存于同一个项目中。

另外,学习一门新的编程语言不一定是为工作所用,也可以给开发者带来新的编程思想,并有可能进一步改变其编程思维。

Scala 相比 Java 在某些特性上有着更出色的表现

不是所有场景下 Scala 都比 Java 更好,但它有一些特性是将来再写 Java 一定会特别想念的,比如那些使代码表达力更强、更安全、更高效的特性。

第一,代码表达力更强

Scala 的代码表达力通过它的类型推导、模式匹配、命名参数与默认值、集合处理、隐式参数或隐式转换来体现。

类型推断

在创建变量时,如果编译器能确定变量的类型,就不需要手动声明了;而这样的操作确实让代码更简洁了。

模式匹配

Scala 模式匹配是一种强大的特性,可以用于检查数据类型、数据结构和数值的匹配,并根据匹配的结果执行相应的代码块。如下图所示,通过模式匹配,我们可以非常简单明了地实现一个获取所有叶子节点值的方法。

下图展示了一些模式匹配的常见用法。模式匹配不仅可以匹配类型,还可以匹配正则表达式,提高正则表达式代码的可读性。同时我们还可以通过定义 unapply 和 unapplySeq 的方式自定义模式匹配的行为。

命名参数 & 默认值

通过下图所呈现的代码,我们可以看到 Scala 可以在一个函数内实现函数参数有默认值,也就是多个函数的重载,而在 Java 开发中实现同样的功能我们往往需要写多个函数。

集合处理

如图中代码所示,通过对比 Java 和 Scala 计算平均工资的方法差异,我们可以容易地发现 Scala 在 Lambda 函数的使用和集合函数的处理上都是更加精简好用的。

隐式参数 / 隐式转换

隐式参数是一种特殊的参数,允许我们在调用函数时不显式地传递参数,而是让编译器根据上下文自动查找并传入相应的参数值。这种功能可以帮助简化代码,提高灵活性,并且常用于依赖注入、类型类和其它模式中。下图展示了隐式参数的使用。

第二,更安全

空指针安全

Java 编程获取 User 列表中最长的名字,需要注意判断空,容易出错。而在 Scala 中,我们可以使用函数式编程方式,避免出现没有判空的错误。

类型安全

Java 编译器允许把 String 数组赋值给 Object 数组,但在运行时当我们尝试给这个 Object 数组插入一个非 String 对象时就会产生错误。这是 Java 编译器在类型安全上的一个问题。同时,Java 编译器不允许把一个 String 列表赋值给 Object 列表,但是从逻辑上来说,我们希望这个这个赋值是可以发生的。而 Scala 编译器则能够解决了这两个问题,它不允许把一个 Sting 数组赋值给一个 Object 数组,但是允许把一个 String 列表赋值给一个 Object 列表。

如下图,我们定义了特质 Animal,Dog 继承 Animal,Husk 继承 Dog。Scala 中 Dog 继承了 Animal的特质,可以当作 Animal 的类型,不能当作 Husky 的类型;但在 Java 中都是不可以的(并不符合常理)。

Scala 编译器通过协变(Covariance)和逆变(Contravariance)来实现上述例子中的的类型安全,这也是为什么 Scala 比 Java 类型系统强大的一个原因。

协变表示类型参数的子类型关系与泛型类型之间的子类型关系是一致的。简而言之,如果类型 A 是类型 B 的子类型,那么 F[A] 也是 F[B] 的子类型。其中,F 表示一个泛型类型。

逆变表示类型参数的子类型关系与泛型类型之间的子类型关系是相反的。简而言之,如果类型 A 是类型 B 的子类型,那么 F[B] 是 F[A] 的子类型。与协变相反,逆变使用逆变符号 - 来表示。

模式匹配检查

Scala 编译器会检查我们的模式匹配代码是否穷举完了所有的 case,当我们忽略了一些 case,编译器会认为代码可能存在逻辑漏洞。这一特性可以很好地帮助我们发现逻辑中的漏洞,让代码更可靠。

第三,更高效

尾递归

Java 中使用递归函数可能会造成栈溢出(某些 Java 编译器在某些情况下会进行尾递归优化);而在 Scala 中,尾递归(Tail Recursion)是指递归函数中的递归调用发生在函数体的最后一个位置。当函数满足尾递归的条件时,编译器可以对其进行尾递归优化。

尾递归优化是一种编译器优化技术,它可以将尾递归函数转化为迭代形式,从而避免在递归过程中产生大量的函数调用栈。这样可以减少内存消耗并提高性能,因为不再需要保存每次递归调用的上下文信息。

如下图,最后一个调用不是该递归函数,则会发生栈溢出,不会进行尾递归的优化。

当稍加修改,在函数中保留一个变量,尾递归优化就可以实现了。

异步编程

在 Scala 中,Future 是表示异步计算结果的一种抽象类型。它允许在一个独立的执行上下文中进行并发计算,并在计算完成后获取结果。Future 通常用于处理异步操作,例如从远程服务器获取数据、执行耗时的计算或 IO 操作等。

在 Scala 中,宏(Macros)是一种元编程机制,允许在编译时对代码进行操作和生成。通过宏,开发人员可以在编译时期以及语法树级别上扩展和改变代码,从而实现更高级的抽象、优化和代码生成。

宏在 Scala 中被广泛应用于各种框架和库中,用于生成重复代码、优化性能、实现领域特定语言(DSL)等方面。然而,宏也是一种强大而复杂的元编程工具,需要谨慎使用,以避免引入难以理解和维护的代码。需要注意的是,自 Scala 2.13 版本起,宏已经被标记为“实验性功能”,而且在 Scala 3 中已经不再推荐使用宏,而是推荐使用新的“引用透明宏”(inline meta)功能。—— 以上总结来自现场观众谷国伟

热门话题讨论

提问:Scala 在实际生产中的应用怎么样?

Chunsen:大家对 Scala 在国内的情况应该比较了解,一直处于不温不火的状态;在国外相对更好。但其实,Scala 依然有很多忠实爱好者,包括我自己。

虽然随着 Java 的发展,语言本身存在缺陷的部分也在逐步弥补。Scala 刚发行时,Java 版本是 1.5,Java 确实存在很多问题影响编程体验,比如泛型尚不成熟、也没有 Lamda,那时 Scala 相对更有优势;而如今 Java 有 Recall /Lamda,也可以支持 Pental Match,这会导致大家对于 Scala 的需求没有那么强了,更何况还存在 Kotlin 这样一款更能抓住 Java 开发者心的、介于 Java 和 Scala 之间的一门编程语言。

但是,在我看来 Scala 依然具备一定的优势,尤其是在你对 Scala 有了更好的掌握和驾驭能力之后。在我使用 Scala 开发的体验中,Scala 确实使我们的代码更高效,业务逻辑更清晰了。

Guobin:如果你的团队相对于技术追求更看重业务本身,那么没有必要一定从 Java 转向 Scala。但是,我们个人学习一门技术或编程语言,并非为了在实际生产环境中使用,而是为了了解 Java 之外的编程思想。比如,作为 Java 开发者,你可能会认为 Lamda 就应该是这样的;但是,当你去学习了 Rust、Kotlin、Scala 等函数式编程语言后,你肯定会问自己“为什么 Java 的 Lamda 这样难用?” 在我看来,这是学习和使用另外一门编程语言所应该实现的效果。

如果你是为了在实际生产环境中使用一门新的编程语言,那么一定要考虑这一选择所带来的代价与收益。比如,当 Java 面对并发这一技术问题时,你可以考虑使用 Scala Akka 这一相对于 Java 非常不同的处理方式。在我看来,最关键的还是要找到“硬需求是什么”。我使用 Scala 的时间比 Java 更长,我有一些个人体验可以分享给大家。面向过程的 Java 开发很容易让人陷入细节的思考中,比如我们通过 Java 实现的算子、折叠方法可能不如标准部件实现得更好。而在 Scala 开发中,我们可以通过充分使用标准部件,避免投入过多的时间在细节的实现上,而将关注点放在更重要更根本的业务实现上。

Qiwen:Tubi 是我第一份写 Scala 的工作,之前我是 Java 开发者。在我看来,了解一门新的语言是为了学习它的写法和思想,而非是为了完全将一种服务从一门语言迁移到另一门语言上。我在 Amazon 工作时做的是Java 开发,虽然当时我们使用的版本是 1.8,但依然保持了一些更老的 Java 习惯。在我开始熟练使用 1.8 的 Lamda 时,会发现很多流程就是一个链,会带来更加清晰简洁的流程描述。当我来到 Tubi 开始写 Scala 时,我发现这竟然是 Scala 天生带有的一种能力,这也给了我机会反观 Java 开发经历。当我了解了 Scala 语言设计的初衷和思想,再回头理解 Java 相对应的一些实现时,我会更理解 Java 这门语言的一些特性,也更会在写代码时遵循那些最佳实践。

Chunsen:我很赞同 Guobin 提到的“在没有硬需求的情况下,没有必要硬转一门新的编程语言”;但我也想补充一点,了解和使用 Scala 一段时间究竟会给开发者带来什么?虽然我们都知道没有什么是 Scala 能实现而 Java 实现不了的,只不过在代码行数和美观性上存在差异,但是使用 Scala 的过程确实改变了我们思考问题的方式。Java 是面向过程的语言,面对一个问题的解决思路是一步一步地找到解决方案,如我在分享中提到的这个例子一样,当你需要在列表中找到用户名最长的用户,Java 的解决思路是使用 loop 循环并在中间加入定义,一步步找到。Scala 的解决思路是首先需要将用户名拿出来,根据用户名的长度排序找到最大的。这是两种完全不同的思维方式。在写了一段时间 Scala 后,我在回顾 Java 代码时会发现有很多可以被优化的地方。对我个人而言,这是我转写 Scala 后的最大收获之一。

欢迎加入 Tubi

Tubi Data Team 目前正在寻找一位大数据平台开发 Lead,他 / 她将领导数据开发团队,创建高质量、可扩展的流数据管道,与所有用户建立联系;将在开放创新的环境中与机器学习团队、产品经理、DevOps 团队和数据科学家合作,推动用户增长;对系统架构设计全面负责,解决性能、可扩展性、可重用性和灵活性等问题;并倡导工程最佳实践,培养与保持团队内的工程师文化;负责技术招聘和指导团队成员的职业发展,建立一支高效的开发团队。

首选编码语言为 Scala、Python 或 Java。

Scala Meetup 往期推荐

Tubi 秉承开放和回馈的心态,自 2019 年 8 月开始赞助并举办 Scala Meetup,如今已成功完成九期线上线下活动。

从 Scala 编程入门学习到职业发展,Scala 函数式编程语言的研究,还有 Scala 的生产实践,你所关心的 Scala 话题在往期 Meetup 中都有所涉及,这些共创交流也正在以某种方式回馈着社区中的每个人,让我们反复思考和精进“为什么选择 Scala?如何可以更好地发挥 Scala 的优势?Scala 怎样可以发展得更好?”

欢迎阅读往期回顾!

【活动回顾】2023年1月

【活动回顾】2022年6月

【活动回顾】2021年1月

【活动回顾】2020年9月

【活动回顾】2020年4月

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/212875.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微服务实战系列之J2Cache

前言 经过近几天陆续发布Cache系列博文,博主已对业界主流的缓存工具进行了基本介绍,当然也提到了一些基本技巧。相信各位盆友看见这么多Cache工具后,在选型上一定存在某些偏爱: A同学说:不管业务千变万化,…

Linux环境下ARM开发

目录 前言ARM启动及开发基础1.Cortex-A架构2.启动方式3.汇编基础4.Makefile语法基础5.Makefile补充6.编译下载 结语 前言 主要介绍基于linux开发环境下,如何开发ARM A7 ARM启动及开发基础 1.Cortex-A架构 1)Cortex-A7运行模式 模式说明User(USR)用户模…

想转行IT,有前途吗?

作为一个在工程领域工作了三年的人,我深知转行到 IT,尤其是网络安全领域,不是一件轻松的事。我的经历或许能为你提供一些启示。 在我之前的工作中,虽然工作量大、压力重,但总觉得缺少了某种成就感和动力。我意识到&a…

SQL Server——权限管理

一。SQL Server的安全机制 SQL Server 的安全性是建立在认证和访问许可两种安全机制之上的。其中.认证用来确定登录Sal Server 的用户的登录账户和密码是否正确.以此来验证其是否具有连接SQL Server 的权限;访问许可用来授予用户或组能够在数据库中执行哪…

Python ItsDangerous库:构建安全可靠的数据传输

更多资料获取 📚 个人网站:ipengtao.com ItsDangerous是Python中一个轻量级的库,旨在提供安全且简单的数据传输和签名功能。本文将深入介绍ItsDangerous的核心特性、基本用法以及在实际应用中的一些示例,通过丰富的示例代码&…

海云安谢朝海:开发安全领域大模型新实践 人工智能助力高效安全左移

2023年11月29日,2023中国(深圳)金融科技大会成功举行,该会议是深圳连续举办的第七届金融科技主题年度会议,也是2023深圳国际金融科技节重要活动之一。做好金融工作,需要兼顾创新与安全,当智能体…

Node.js入门指南(完结)

目录 接口 介绍 RESTful json-server 接口测试工具 会话控制 介绍 cookie session token 上一篇文章我们介绍了MongoDB,这一篇文章是Node.js入门指南的最后一篇啦!主要介绍接口以及会话控制。 接口 介绍 接口是前后端通信的桥梁 &#xff0…

微信小程序基础

1.小程序发展史 微信小程序之前,是使用weixin-sdk进行开发,调用视频,摄像头等。 微信小程序weixin up端,所以PC端的window这些没有,运行环境是IOS,安卓等,有一些特殊的调用录音功能&#xff0…

微服务1 springcloud学习笔记P1-P40

b微服务技术栈_哔哩哔哩_bilibili 文档资料: 链接:https://pan.baidu.com/s/1P_Ag1BYiPaF52EI19A0YRw?pwdd03r 提取码:d03r 一 了解微服务技术 二 Eureka (1) Eureka配置 (2) 注册user-service (3) 总结 Ribbon 负载均衡 (1) 流程 三 nacos配置管理…

公众号提高数量

一般可以申请多少个公众号?目前公众号申请数量的规定是从2018年底开始实施的,至今没有变化。规定如下:1、个人可以申请1个个人主体的公众号;2、企业(有限公司)可以申请2个公众号;3、个体户可以申…

初识消息队列

1、消息 消息(Message)是指在应用间传送的数据。消息可以非常简单,比如只包含文本字符串,也可以更复杂,可能包含嵌入对象。 2、消息队列 消息队列(Message Queue)是一种应用间的通信方式&#…

12.8作业

1.头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QDebug> #include <QMovie>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nul…

【无线网络技术】——无线局域网(学习笔记)

&#x1f4d6; 前言&#xff1a;本章首先介绍无线局域网的基本概念&#xff0c;然后详细介绍IEEE 802.11的基本工作原理&#xff0c;侧重于媒体访问控制和一跳范围内的通信技术。 目录 &#x1f552; 1. 概述&#x1f558; 1.1 覆盖范围&#x1f558; 1.2 特点&#x1f558; 1.…

SIT3232E高静电防护,单电源供电,双通道,RS232 收发器

SIT3232E 是一款 3.0V~5.5V 供电、双通道、低功耗、高静电防护 ESD 保护&#xff0c;完全满足 TIA/EIA-232 标准要求的 RS-232 收发器。 SIT3232E 包括两个驱动器和两个接收器&#xff0c;具有增强形 ESD 保护功能&#xff0c;达到 15kV 以上 HBM ESD 、 8kV …

为什么Java程序员需要掌握多线程?揭秘并发编程的奥秘

为什么Java程序员需要掌握多线程&#xff1f;揭秘并发编程的奥秘 个人简介前言多线程对于Java的意义&#x1f4cc;1.提高程序性能&#xff1a;&#x1f4cc;2 提高用户体验&#xff1a;&#x1f4cc;3支持并发处理&#xff1a;&#x1f4cc;4 资源共享和同步&#xff1a;&#…

【Python】Python读Excel文件生成xml文件

目录 ​前言 正文 1.Python基础学习 2.Python读取Excel表格 2.1安装xlrd模块 2.2使用介绍 2.2.1常用单元格中的数据类型 2.2.2 导入模块 2.2.3打开Excel文件读取数据 2.2.4常用函数 2.2.5代码测试 2.2.6 Python操作Excel官方网址 3.Python创建xml文件 3.1 xml语法…

Android MVVM+coroutine+retrofit+flow+hilt

文章目录 Android MVVMcoroutineretrofitflowhilt概述依赖注入层数据层视图层模型视图层代码下载 Android MVVMcoroutineretrofitflowhilt 概述 代码结构&#xff1a; 依赖注入层 数据库&#xff1a; Module InstallIn(SingletonComponent::class) class DBModule {Singleto…

IP地址定位技术:追踪位置、识别风险

随着互联网的普及&#xff0c;IP地址定位技术逐渐成为网络安全领域的一项重要工具。通过追踪IP地址位置&#xff0c;可以识别潜在的风险用户&#xff0c;加强网络安全。本文将深入研究IP地址定位技术的原理、应用以及相关的风险与防范。 1. IP地址定位技术的原理&#xff1a; …

C语言——2048完整版

2048是一个简单又有趣的小游戏&#xff0c;相信大家都接触并了解过&#xff0c;那如何通过代码来实现他呢&#xff1f;下面就让我们来一起看看。 目录 1、头文件 2、主函数 3、 StarGame 4、GetNum 5、Show 6、Picture 7、GetButton 8、MergeLeft 9、MergeUp 10、MergeR…

webpack优化打包速度

webpack打包速度太慢 优化 1.多线程打包 js压缩和loader 2.优化启动速度 hard-source-webpack-plugin 3.删除无用的 分析类插件 4.DllPlugin通道打包 1.webpack多线程打包 loader loader 使用 thread-loader 将他放置你要使用的loader前面就行&#xff0c;不过这个lorder例如s…