为什么每个 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.mzph.cn/news/207277.shtml

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

相关文章

【投稿优惠|检索稳定】2024年信息系统、工程与数字化经济国际会议(ICISEDE 2024)

2024年信息系统、工程与数字化经济国际会议(ICISEDE 2024) 2024 International Conference on Information Systems and Engineering and the Digital Economy(ICISEDE 2024) [会议简介] 2024 年信息系统、工程与数字化经济国际会议(ICISEDE 2024)将于 2024 年 1 月 20 日在厦门…

Endnote在word中加入参考文献及自定义参考文献格式方式

第一部分:在word中增加引用步骤 1、先下载对应文献的endnote引用格式,如在谷歌学术中的下载格式如下: 2、在endnote中打开存储env的格式库,导入对应下载的文件格式:file>import>file>choose,import对应文件&a…

IT外包驻场加速企业IT创新

随着科技的快速发展,企业在追求创新和应用IT技术方面面临挑战。IT外包驻场服务成为许多企业的选择,助力企业实现快速、高效的IT项目实施和应用。 IT外包驻场服务的主要目标是帮助企业在IT创新方面取得突破。这种服务模式不仅仅是提供技术支持&#xff0c…

配电室无人值守改造

配电室无人值守改造是通过运用先进的技术和设备,将传统的需要人工值守的配电室改造成可以远程监控和管理的智能化配电室,从而实现无人值守。这种改造可以提高配电室的安全性、可靠性和效率,降低运维成本。 建立智能监控系统:通过安…

Vue3选项式-基础部分篇

Vue3选项式风格-基础部分篇 简介模板语法文本插值原始HTMLAttribute 绑定使用 JavaScript 表达式调用函数全局组件调用内置指令动态参数注意事项 data()data()深度响应 methods有状态的methods(防抖) DOM更新时机计算属性class和style绑定条件渲染列表渲染数组变换侦听事件处理…

echart中定义brush,默认状态,触发状态

1.定义矩形选择笔刷:brush 2.设置brush的默认状态和选中逻辑

理解VAE(变分自编码器)

1.贝叶斯公式 贝叶斯理论的思路是,在主观判断的基础上,先估计一个值(先验概率),然后根据观察的新信息不断修正(可能性函数)。 P(A):没有数据B的支持下,A发生的概率,也叫做先验概率。…

小视频怎么做成二维码?视频二维码3步生成

在日常工作和生活中经常会看到各种类型的小视频、短视频,比如网页、抖音等等的视频都是可以下载查看的。当我们想要将下载视频分享给多个人看时,生成二维码的方式会更加的方便,那么视频如何生成二维码呢?下面就将快捷生成二维码的…

第75讲:MySQL数据库MVCC多版本并发控制核心概念以及底层原理

文章目录 1.当前读与快照读的基本概念1.1.当前读的基本概念1.2.快照读的基本概念 2.什么是MVCC多版本并发控制3.MVCC多版本并发控制依赖的三个组件重要概念3.1.MySQL表中三个隐式字段的概念3.2.undo log日志以及版本链的概念3.3.ReadView读视图的概念 4.MVCC实现多版本并发控制…

【FPGA】Verilog:BCD 加法器的实现

0x00 XOR 运算在 2 的补码加减法中的应用 2 的补码加减法的特点是,当从某个数中减去负数时,将其转换为正数的加法来计算,并将减去正数的情况转换为负数的加法来计算,从而将所有减法运算转换为加法运算。在这种情况下,…

SpringAMQP 快速入门

SpringAMQP 快速入门 1. 创建项目2. 快速入门2.2.1 消息发送2.2.2 消息接收 3. 交换机3.1 Fanout Exchange(扇出交换机)3.1.1 创建队列与交换机3.1.2 消息接收3.1.3 消息发送 3.2 Direct Exchange(直连交换机)3.2.1 创建交换机与队…

Validate 验证规则详解

前言: 以前小编发过一篇Validate 验证规则 如何使用的,没有去将Validate 验证规则的原理应用场景,这篇文章来完善一下。 不知道如何使用的朋友可以点击下面传送门 传送门 讲解: Validate 验证规则通常指的是在 Web 开发中,使用验证器&…

【开源】基于Vue.js的智慧社区业务综合平台

文末获取源码,项目编号: S 077 。 \color{red}{文末获取源码,项目编号:S077。} 文末获取源码,项目编号:S077。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 业务类型模块2.2 基础业务模块2.3 预…

精选Axure原型设计模板,RP原型组件库(PC端移动端元件库及Axure函数及运算符说明)

好的原型组件会大大的提高产品经理的工作效率,现精选了一批Axure 8的原型设计模板,包含了原型设计的常用元素和AxureRP 8函数及运算符的说明文档,及各种设备模板框架。 分享给大家可以共同学习,文末可下载完整原型组件包~&#x…

苹果手机ios系统安装了一个免签应用书签webclip描述文件该如何卸载?

随着移动应用的普及,越来越多的用户开始关注到苹果免签的应用。相比于需要通过 App Store 审核和签名的应用,免签应用无需经过苹果的审核过程,可以直接安装和使用。那么,苹果免签应用是如何制作的呢?本文将介绍制作苹果…

SQL进阶 | CASE表达式

本文所有案例基于《SQL进阶教程》实现。 概述 SQL中的CASE表达式是一种通用的条件表达式,类似于其他语言中的if/else语句。它用于在SQL语句中实现条件逻辑。CASE表达式以WHEN子句开始,后面跟着一个或多个WHEN条件,每个WHEN条件后面跟着一个TH…

C++相关闲碎记录(3)

1、reference wrapper 例如声明如下的模板&#xff1a; template <typename T> void foo(T val); 如果调用使用&#xff1a; int x; foo(std::ref(x)); T变成int&&#xff0c;而使用调用 int x; foo(std::cref(x)); T变成const int&。 这个特性被C标准库用…

fijkplayer flutter 直播流播放

fijkplayer flutter 直播流播放 fijkplayer 是 ijkplayer 的 Flutter 封装&#xff0c; 是一款支持 android 和 iOS 的 Flutter 媒体播放器插件&#xff0c; 由 ijkplayer 底层驱动。 通过纹理&#xff08;Texture&#xff09;接入播放器视频渲染到 Flutter 中。 前言 目前使用…

PostgreSQL 技术内幕(十二) CloudberryDB 并行化查询之路

随着数据驱动的应用日益增多&#xff0c;数据查询和分析的量级和时效性要求也在不断提升&#xff0c;对数据库的查询性能提出了更高的要求。为了满足这一需求&#xff0c;数据库引擎不断经历创新&#xff0c;其中并行执行引擎是性能提升的重要手段之一&#xff0c;逐渐成为数据…