大家好🙌我是你们的好朋友,程序员乌拉😀。相遇是缘,既然来了就拎着小板凳坐下来一起唠会儿😎,如果在文中有所收获,请别忘了一键三连,动动你发财的小手👍,你的鼓励,是我创作的动力😁!废话不多说,直接😎 开干吧!

==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值类型,如Intand Boolean)和AnyRef引用类型,如 Java)。这意味着原始类型和装箱类型(例如intvs. 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 代码。关于第二点,像AkkaPlay 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,usingextension,重点关注机制之上的意图
    • 扩展方法用更清晰和更简单的机制替换隐式类
    • 为类添加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开发团队。

image.png

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 也有whiledo/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 集合类—— ListListBufferVectorArrayBufferMapSet。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
序列方法

顺序集合类 — ArrayArrayBufferVectorList等, 使用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

元组的值也可以使用模式匹配来提取。在示例中,元组内的字段被分配给变量symbolpricevolume

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语言书籍