大家好🙌我是你们的好朋友,程序员乌拉😀。相遇是缘,既然来了就拎着小板凳坐下来一起唠会儿😎,如果在文中有所收获,请别忘了一键三连,动动你发财的小手👍,你的鼓励,是我创作的动力😁!废话不多说,直接😎 开干吧!
==PS:文末干货,记得拎着小板凳离开的时候也给它顺走== 🤣 座右铭:“懒”对一个人的毁灭性有多大,早起的重要性就多大。
(Scala概述)
Scala概述
Scala概述
Scala是一种美丽、现代、富有表现力的编写语言。Scala源于可扩展
这个词,正如这个名字一样,Scala语言用于为复杂的编程提供动力和分析庞大的数据集。
Scala特点
- 它是一种高级编程语言
- 它具有简洁易读的语法
- 它是静态类型的(但感觉是动态的)
- 它有一个富有表现力的类型系统
- 它是一种函数式编程 (FP) 语言
- 它是一种面向对象的编程 (OOP) 语言
- 支持FP和OOP的融合
- 上下文抽象提供了一种清晰的方式来实现术语推理
- 它在 JVM(和浏览器)上运行
- 它与 Java 代码无缝交互
- 它用于服务器端应用程序(包括微服务)、大数据应用程序,也可以在带有 Scala.js 的浏览器中使用
Scala 至少在两个方面被认为是一种高级语言:
1、首先,与 Java 和许多其他现代语言一样,不需要处理指针和内存管理等低级概念。
2、 其次,通过使用 lambda 和高阶函数,可以在非常高的层次上编写代码。正如函数式编程所说,在 Scala 中,编写想要的,而不是如何实现它。
简洁的语法
Scala具有简洁易读的语法。例如,变量被创建,其本身的类型是明确的:
val nums = List(1, 2, 3)
val p = Person("Tom", "Jack")
高阶函数和lambdas代码简洁易读:
nums.map(i => i * 2)
nums.map(_ * 2)
nums.filter(i => i > 1)
nums.filter(_ > 1)
特征、类、方法是使用简洁的语法定义:
trait Animal:
def speak(): Unit
trait HasTail:
def wagTail(): Unit
class Dog extends Animal, HasTail:
def speak() = println("Woof")
def wagTail() = println("⎞⎜⎛ ⎞⎜⎛")
动态性
Scala是一种静态类型的语言,因为它本身具有类型推断能力,所以给人感觉是动态的:
val s = "Hello"
val p = Person("Al", "Pacino")
val sum = nums.reduceLeft(_ + _)
val y = for i <- nums yield i * 2
val z = nums.filter(_ > 100)
.filter(_ < 10_000)
.map(_ * 2)
Scala本任务是一种清大的静态类型语言,其静态类型的好处是:
- 正确性:在编译时捕获代码逻辑的错误
- 强大的IDE支持
- 在编译时捕获错误
- 简单可靠的重构
- 可重构代码
- 方法类型声明该方法的作用,并作为帮助文档
- 可扩展性和可维护性: 类型有助于确保跨任意大型应用程序和开发团队的正确性
- 强类型与出色的推理相结合,可以实现上下文抽象等机制,允许省略代码。通常,编译器可以根据类型定义和给定的上下文推断出这个样板代码。
函数式编程语言
Scala 是一种函数式编程 (FP) 语言,意思是:
- 函数是值,可以像任何其他值一样传递
- 直接支持高阶函数
- Lambda 是内置的
- Scala 中的一切都是返回值的表达式
- 从语法上讲,使用不可变变量很容易,并且鼓励使用它们
- 它在标准库中有丰富的不可变集合类
- 这些集合类带有许多功能方法:它们不会改变集合,而是返回数据的更新副本
面向对象语言
Scala 是一种面向对象的编程 (OOP) 语言。每个值都是一个类的实例,每个“操作符”都是一个方法。在 Scala 中,所有类型都继承自顶级类Any
,其直接子类是AnyVal
(值类型,如Int
and Boolean
)和AnyRef
(引用类型,如 Java)。这意味着原始类型和装箱类型(例如int
vs. Integer
)之间的 Java 区别在 Scala 中不存在。装箱和拆箱对用户完全透明。
支持FP/OOP融合
Scala 的本质是函数式编程和面向对象编程在类型化设置中的融合:
- 逻辑函数
- 模块化对象
正如Martin Odersky 所说,“Scala 旨在表明函数式编程和面向对象编程的融合是可能的和实用的。”
术语推断,更清晰
Scala 是第二个具有某种形式的隐式的流行语言。核心思想是术语推断:给定一个类型,编译器合成一个具有该类型的“规范”术语。在 Scala 中,上下文参数直接导致推断的参数项,也可以显式地写下来。这个概念的用例包括实现类型类、建立上下文、依赖注入、表达能力、计算新类型以及证明它们之间的关系。
Scala 代码在 Java 虚拟机 (JVM) 上运行,因此它的好处:
- 安全
- 表现
- 内存管理
- 可移植性和平台独立性
- 使用丰富的现有 Java 和 JVM 库的能力
除了在 JVM 上运行之外,Scala 还使用 Scala.js(以及集成流行 JavaScript 库的开源第三方工具)在浏览器中运行,并且可以使用 Scala Native 和 GraalVM 构建原生可执行文件。
无缝与Java 交互
可以在 Scala 应用程序中使用 Java 类和库,也可以在 Java 应用程序中使用 Scala 代码。关于第二点,像Akka和Play Framework这样的大型库是用 Scala 编写的,可以在 Java 应用程序中使用。
Java 类和库每天都在 Scala 应用程序中使用。例如,在 Scala 中,您可以使用 JavaBufferedReader
和读取文件FileReader
:
import java.io.*
val br = BufferedReader(FileReader(filename))
在 Scala 中使用 Java 代码通常是无缝的。Java 集合也可以在 Scala 中使用,如果您想将 Scala 丰富的集合类方法与它们一起使用,只需几行代码即可转换它们:
import scala.jdk.CollectionConverters.*
val scalaList: Seq[Integer] = JavaClass.getJavaList().asScala.toSeq
优势:
- 使用枚举更简洁地创建代数数据类型 (ADT) 的能力
- 更简洁易读的语法:
- “安静”的控制结构语法更易于阅读
- 可选大括号
- 代码中更少的符号会产生更少的视觉噪音,使其更易于阅读
new
创建类实例时一般不再需要该关键字- 包对象的形式已被删除,有利于更简单的“顶级”定义
- 更清晰的语法:
implicit
关键字的多种不同用途已被删除;这些用法被更明显的关键字所取代,例如given
,using
和extension
,重点关注机制之上的意图- 扩展方法用更清晰和更简单的机制替换隐式类
- 为类添加
open
修饰符使开发人员有意声明一个类可以修改,从而限制对代码库的临时扩展 - 多元等式排除了与
==
and的无意义比较!=
(即,尝试将 aPerson
与 a进行比较Planet
) - 宏更容易实现
- 并集和交集为模型类型提供了一种灵活的方式
- 特征参数替换和简化早期初始化器
- 不透明类型别名替换了值类的大多数用途,同时保证不存在装箱
- 导出子句提供了一种简单而通用的方式来表达聚合,它可以替代之前封装对象从类继承的外观模式
- 过程语法已被删除,可变参数语法已被更改,两者都使语言更加一致
@infix
注释清楚地表明您希望如何应用方法- 方法注释定义了方法的
@targetName
替代名称,提高了 Java 互操作性,并允许符号运算符提供别名
Scala语言的诞生
创始人马丁·奥德斯基(Martin Odersky)是编译器及编程的狂热爱好者,长时间的编程之后,希望发明一种语言,能够让编程程序这样的基础工作变得更加高效、简单。所以当接触Java语言后,对Java这门便携式、运行在网络上、且存在垃圾回收的语言产生了极大的兴趣,所以决定将函数式编程语言的特点融入到Java种,由此发明了两种语言(Pizza&Scala)。
Pizza和Scala极大地推动了Java编程语言的发展:
JDK5.0中的泛型、for循环增强、自动类型转换等,都是从Pizza引入的新特性。JDK8.0的类型推断、Lambda变大时就是从Scala引入的特性。且现在主流的JVM的javac编译器就是马丁·奥德斯基编程的。JDK5.0、JDK8.0的编译器也是马丁·奥德斯基编写的。因此马丁·奥德斯基一个人的战斗力抵得上一个Java开发团队。
Hello World
自从《C Programming Language 》一书以来,以“Hello, world”示例开始编程已经成为一种传统,而且不会让人失望,这是用 Scala 编写该示例的一种方法:
Object HelloWorld{
println("Hello, World")
}
Scala REPL
Scala REPL(“Read-Evaluate-Print-Loop”)是一个命令行解释器,可以将其用来测试 Scala 代码。
启动 REPL 会话,只需scala
在操作系统命令行中输入scala
即可。
PS C:\WINDOWS\system32> scala
Welcome to Scala 2.12.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_301).
Type in expressions for evaluation. Or try :help.
scala>
REPL 是一个命令行解释器,在 REPL 中键入 Scala 表达式以查看它们是如何工作的:
scala> val x = 1
x: Int = 1
scala> val y = x + 1
y: Int = 2
在 REPL 中键入表达式后,它会在提示符后的行上显示每个表达式的结果
两种类型的变量
Scala 有两种类型的变量:
val
是一个不可变的变量——就像final
在 Java 中一样——应该是首选var
创建一个可变变量,并且只应在有特定原因使用它时使用- 例子:
val x = 1 //immutable 不可变的
var y = 0 //mutable 可变的
==强烈建议使用val进行变量的定义==
声明变量类型
在 Scala 中,通常创建变量而不声明它们的类型:
val x = 1
val s = "a string"
val p = new Person("Tom")
Scala 通常可以自动推断数据类型,如以下 REPL 示例所示:
scala> val x = 1
val x: Int = 1
scala> val s = "a string"
val s: String = a string
此功能称为类型推断,它是帮助保持代码简洁的好方法。也可以显式声明变量的类型,但这通常不是必需的:
val x: Int = 1
val s: String = "a string"
val p: Person = new Person("Tom")
控制结构
if-else
Scala 的 if/else 控制结构与其他语言类似:
if (test1) {
doA()
} else if (test2) {
doB()
} else if (test3) {
doC()
} else {
doD()
}
与 Java 和许多其他语言不同,if/else 构造返回一个值,因此,除其他外,可以将其用作三元运算符:
val x = if (a < b) a else b
模式匹配
Scala 有一个match
表达式,它最基本的用途类似于 Javaswitch
语句:
val result = i match {
case 1 => "one"
case 2 => "two"
case _ => "not 1 or 2"
}
该match
表达式不仅限于整数,它可以与任何数据类型一起使用,包括布尔值:
val booleanAsString = bool match {
case true => "true"
case false => "false"
}
match
方法主体的示例,并与许多不同的类型进行匹配:
def getClassAsString(x: Any):String = x match {
case s: String => s + " is a String"
case i: Int => "Int"
case f: Float => "Float"
case l: List[_] => "List"
case p: Person => "Person"
case _ => "Unknown"
}
异常捕获
Scala 的 try/catch 控制结构让可以捕获异常。它与 Java 类似,但其语法与匹配表达式一致:
try {
writeToFile(text)
} catch {
case fnfe: FileNotFoundException => println(fnfe)
case ioe: IOException => println(ioe)
}
for循环
Scalafor
循环——通常将其写成for 循环——看起来像这样:
for (arg <- args) println(arg)
// "x to y" syntax
for (i <- 0 to 5) println(i)
// "x to y by" syntax
for (i <- 0 to 10 by 2) println(i)
还可以将yield
关键字添加到 for 循环以创建产生结果的 for 表达式。这是一个将序列 1 到 5 中的每个值加倍的 for 表达式:
val x = for (i <- 1 to 5) yield i * 2
另外一种对遍历字符串列表的 for 表达式:
val fruits = List("apple", "banana", "lime", "orange")
val fruitLengths = for {
f <- fruits
if f.length > 4
} yield f.length
while&do/while
Scala 也有while
和do
/while
循环。这是它们的一般语法:
// while loop
while(condition) {
statement(a)
statement(b)
}
// do-while
do {
statement(a)
statement(b)
}
while(condition)
创建类
Scala 类的例子:
class Person(var firstName: String, var lastName: String) {
def printFullName() = println(s"$firstName $lastName")
}
使用该类的方法:
val p = new Person("Julia", "Kern")
println(p.firstName)
p.lastName = "Manes"
p.printFullName()
请注意,无需创建“get”和“set”方法来访问类中的字段。
复杂的案例:
class Pizza (
var crustSize: CrustSize,
var crustType: CrustType,
val toppings: ArrayBuffer[Topping]
) {
def addTopping(t: Topping): Unit = toppings += t
def removeTopping(t: Topping): Unit = toppings -= t
def removeAllToppings(): Unit = toppings.clear()
}
在该代码中, anArrayBuffer
类似于 Java 的ArrayList
. 、和类未显示CrustSize
,无需查看这些类即可理解该代码的工作原理。CrustType``Topping
method(方法)
就像其他 OOP 语言一样,Scala 类也有方法,这就是 Scala 方法语法的样子:
def sum(a: Int, b: Int): Int = a + b
def concatenate(s1: String, s2: String): String = s1 + s2
不必声明方法的返回类型,可以像这样编写这两个方法是完全合法的:
def sum(a: Int, b: Int) = a + b
def concatenate(s1: String, s2: String) = s1 + s2
调用方法的方式:
val x = sum(1, 2)
val y = concatenate("foo", "bar")
特质
Scala 中的特征非常有趣,它们还可以让将代码分解为小的模块化单元。类似于Java中的interface:
trait Speaker {
def speak(): String
}
trait TailWagger {
def startTail(): Unit = println("tail is wagging")
def stopTail(): Unit = println("tail is stopped")
}
trait Runner {
def startRunning(): Unit = println("I’m running")
def stopRunning(): Unit = println("Stopped running")
}
创建一个Dog
扩展所有这些特征的类,同时为该speak
方法提供行为:
class Dog(name: String) extends Speaker with TailWagger with Runner {
def speak(): String = "Woof!"
}
展示如何覆盖多个 trait 方法的类-- Cat
:
class Cat extends Speaker with TailWagger with Runner {
def speak(): String = "Meow"
override def startRunning(): Unit = println("Yeah ... I don’t run")
override def stopRunning(): Unit = println("No need to stop")
}
集合
基本的 Scala 集合类—— List
、ListBuffer
、Vector
、ArrayBuffer
、Map
和Set
。Scala 集合类的一大好处是它们提供了许多强大的方法。
列表的使用
val nums = List.range(0, 10) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
val nums = (1 to 10 by 2).toList
val letters = ('a' to 'f').toList
val letters = ('a' to 'f' by 2).toList
序列方法
顺序集合类 — Array
、ArrayBuffer
、Vector
、List
等, 使用List
:
val nums = (1 to 10).toList
val names = List("joel", "ed", "chris", "maurice")
foreach
方法
scala> names.foreach(println)
joel
ed
chris
maurice
filter
方法,然后是foreach
:
scala> nums.filter(_ < 4).foreach(println)
1
2
3
map
方法示例:
scala> val doubles = nums.map(_ * 2)
doubles: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
scala> val capNames = names.map(_.capitalize)
capNames: List[String] = List(Joel, Ed, Chris, Maurice)
scala> val lessThanFive = nums.map(_ < 5)
lessThanFive: List[Boolean] = List(true, true, true, true, false, false, false, false, false, false)
map
工作原理:它将您提供的算法应用于集合中的每个元素,为每个元素返回一个新的转换值。
最强大的集合方法之一,foldLeft
:
scala> nums.foldLeft(0)(_ + _)
res0: Int = 55
scala> nums.foldLeft(1)(_ * _)
res1: Int = 3628800
to 的第一个参数foldLeft
是种子值,可以猜测第一个示例产生中的数字的总和nums
,而第二个示例返回所有这些数字的乘积。
元组
元组可以将异构的元素集合放在一个小容器中。一个元组可以包含 2 到 22 个值,并且所有值都可以具有不同的类型。例如,这是一个包含三种不同类型 an Int
、 aDouble
和 a的元组String
:
(11, 11.0, "Eleven")
这被称为 a Tuple3
,因为它包含三个元素。
元组在许多地方使用都很方便,例如,可能使用其他语言的临时类。例如,可以从方法返回元组而不是返回类:
def getAaplInfo(): (String, BigDecimal, Long) = {
("AAPL", BigDecimal(123.45), 101202303L)
}
将该方法的结果分配给一个变量:
val t = getAaplInfo()
通过数字访问它的值,前面加下划线:
t._1
t._2
t._3
使用 REPL 访问字段的结果:
scala> t._1
res0: String = AAPL
scala> t._2
res1: scala.math.BigDecimal = 123.45
scala> t._3
res2: Long = 101202303
元组的值也可以使用模式匹配来提取。在示例中,元组内的字段被分配给变量symbol
、price
和volume
:
val (symbol, price, volume) = getAaplInfo()
使用 REPL 访问字段的结果:
scala> val (symbol, price, volume) = getAaplInfo()
symbol: String = AAPL
price: scala.math.BigDecimal = 123.45
volume: Long = 101202303
文末彩蛋🤩
🚗🤩😉💖🌹👀✨给各位朋友安利一下平时收集的各种学习资料!!!有需要的朋友点击一下⏩传送门,自行领取。程序员经典名言:"收藏了就等于学会啦"。 做人也要像蜡烛一样,在有限的一生中有一分热发一份光,给人以光明,给人以温暖! 图灵程序丛书300+ Linux实战100讲 Linux书籍 计算机基础硬核总结 计算机基础相关书籍 操作系统硬核总结 Java自学宝典 Java学习资料 Java硬核资料 Java面试必备 Java面试深度剖析 阿里巴巴Java开发手册 MySQL入门资料 MySQL进阶资料 深入浅出的SQL Go语言书籍