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

news2024/11/18 11:48:06

前面我们一起回顾了第九期 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.coloradmin.cn/o/1294936.html

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

相关文章

Linux 进程优先级

什么是进程的优先级 优先级:对资源的访问顺序!注意优先级与权限的区别,优先级决定的是访问资源的顺序,这意味着无论是谁都可以访问到资源;但是如果你没有权限,你是不能访问资源的! 这个应该比较…

XXL-JOB日志相关报错的原因

1.问题:msg:job handler [myJobHandler] not found. 原因:执行器中没有对应的执行器。 执行器中代码展示: Component Slf4j public class JobHandler {XxlJob(value "abcHandler")public void abcHandler() {log.inf…

卷积神经网络中用1*1 卷积有什么作用或者好处呢?

一、来源:[1312.4400] Network In Network (如果11卷积核接在普通的卷积层后面,配合激活函数,即可实现network in network的结构) 二、应用:GoogleNet中的Inception、ResNet中的残差模块 三、作用&#x…

【C++】:STL源码剖析之vector类容器的底层模拟实现

&#x1f4da;1.vector接口总览 namespace lyp {//模拟实现vectortemplate<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;//默认成员函数vector(); //构造函数vector(size_t n, const …

微信小程序 - 创建 ZIP 压缩包

微信小程序 - 创建 ZIP 压缩包 场景分享代码片段导入 JSZip创建ZIP文件追加写入文件测试方法参考资料 场景 微信小程序只提供了解压ZIP的API&#xff0c;并没有提供创建ZIP的方法。 当我们想把自己处理好的保存&#xff0c;打包ZIP保存下来时就需要自己实现了。 分享代码片段…

freeswitch如何解决sip信令的NAT问题

概述 freeswitch是一款简单好用的VOIP开源软交换平台。 公网环境复杂多变&#xff0c;客户环境更是各种稀奇古怪的问题。 fs在针对sip信令的NAT问题有针对性的参数设置。 本文讨论的范围限于fs的公网地址正常没有在NAT后面的两种常见场景。其他更多更复杂的NAT场景暂不讨论…

滴滴公布故障原因

故障原因公布&#xff1a; “底层系统软件发生故障” 业界传闻是因 “K8s升级版本错误导致”。 巧的是&#xff0c;在 10 月 17 日 “滴滴技术” 发布的《滴滴弹性云基于 K8S 的调度实践》一文中&#xff0c;也刚好有介绍滴滴从 K8s 1.12 到 1.20 跨版本升级的方案。在替换方案…

喜讯!云起无垠上榜《成长型初创企业推荐10强》

近期&#xff0c;由中国计算机学会抗恶劣环境计算机专业委员会、信息产业信息安全测评中心和安全牛联合发起的第十一版《中国网络安全企业100强》榜单正式发布。在这份备受关注的榜单中&#xff0c;云起无垠凭借其创新的技术能力&#xff0c;荣登《成长型初创企业推荐10强》榜单…

FPGA入门有多难?这篇文章让你吃透零基础入门技巧!

FPGA是一个高度集成化的芯片&#xff0c;其学习过程既需要编程&#xff0c;又需要弄懂硬件电路和计算机架构。涉及到的知识和基础非常多&#xff0c;如果不合理地安排学习内容&#xff0c;学习过程会非常漫长和枯燥。这使很多想要学习FPGA小伙伴望而却步&#xff0c;那么&#…

RHEL8_Linux网络时间服务器

本章主要介绍网络时间服务器 使用chrony配置时间服务器配置chrony客户端向服务器同步时间 1.时间同步的必要性 一些服务对时间要求非常严格&#xff0c;例如&#xff0c;图20-1所示的由三台服务器搭建的ceph集群。 这三台服务器的时间必须保持一致&#xff0c;如果不一致&…

如何选择合适的运筹优化求解器?

文章目录 前言求解器对比问题延伸&#xff1a;商用求解器和开源求解器的差别是什么&#xff1f; 求解器PK总结参考资料 前言 求解器对于运筹算法工程师而言&#xff0c;常常像一个黑盒&#xff0c;我们扔进去输入数据和数学模型&#xff0c;求解器给我们吐出一个解出来。这种状…

类与对象的概念:创建及调用方法

掌握类和创建对象的关系 定义类 定义对象 定义和调用方法 编程思想&#xff1a;面向过程编程&#xff0c;面向对象编程 系统提供数据类型【String&#xff0c;char&#xff0c;double】&#xff0c;我们也可以自己定义类型&#xff1a;根据自定义类型所衍生出来的变量就是…

【推荐系统】推荐算法数学基础

【大家好&#xff0c;我是爱干饭的猿&#xff0c;本文重点介绍推荐系统涉及的数学知识、推荐系统涉及的概率统计知识。 后续会继续分享其他重要知识点总结&#xff0c;如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下吧】 上一篇文章&#xff1a;《【推…

RocketMq顺序消息

RocketMq顺序消息 1.RocketMq 架构图2.RocketMq顺序消息2.1部分消息有序2.1.1 生产者构建2.1.2 生产者保证有序2.1.3 消费者保证有序性 3.使用rocketmq-spring-boot-starter发送消息如何指定tag与key?问题1.MessagingException: sendDefaultImpl call timeout 1.RocketMq 架构…

高精度加法,减法,乘法,除法(下)(C语言)

前言 上一篇博客我们分享了高精度加法&#xff0c;减法,这一期我将为大家讲解高精度乘法和高精度除法。那让我们开始吧&#xff01; 对加法和减法感兴趣的话就点我 文章目录 1&#xff0c;乘法2&#xff0c;除法3&#xff0c;尾声 1&#xff0c;乘法 让我们想想我们平时做数学…

STC15F100E单片机模拟串口

文章目录 一、芯片简介二、开发环境三、软件模拟串口参考 一、芯片简介 STC15F100系列单片机是宏晶科技生产的单时钟/机器周期(1T)的单片机&#xff0c;新一代8051单片机&#xff0c;指令代码完全兼容传统8051&#xff0c;但是速度快6-12倍。 内部集成R/C时钟&#xff0c;5MHz…

52 代码审计-PHP项目类RCE及文件包含下载删除

目录 漏洞关键字:演示案例:xhcms-无框架-文件包含跨站-搜索或应用-includeearmusic-无框架-文件下载-搜索或应用功能-down等zzzcms-无框架-文件删除RCE-搜索或应用-unlink、eval 漏洞关键字: SQL注入&#xff1a; select insert update mysql_query mysql等 文件上传&#xff…

守护安全,六氟化硫气体泄漏报警装置校准服务

在电力工业中&#xff0c;六氟化硫&#xff08;SF6&#xff09;气体是一种重要的介质&#xff0c;它用作封闭式中、高压开关的灭弧和绝缘气体。六氟化硫气体的卓越性能实现了装置经济化、低维护化的操作。与普通装置相比&#xff0c;可以节省最多90&#xff05;的空间。 六氟化…

Themis: Fast, Strong Order-Fairness in Byzantine Consensus

目录 笔记后续的研究方向摘要引言秩序井然 Themis: Fast, Strong Order-Fairness in Byzantine Consensus CCS 2023 笔记 后续的研究方向 摘要 我们介绍了Themis&#xff0c;这是一种将交易的公平排序引入&#xff08;许可的&#xff09;拜占庭共识协议的方案&#xff0c;最…