1.概述
1.1特点
Scala 是一门以 java 虚拟机(JVM)为运行环境并将面向对象和函数式编程的最佳特性结合在一起
的静态类型编程语言。
1) Scala 是一门多范式 (multi-paradigm) 的编程语言,Scala 支持面向对象和函数式编程
2) Scala源代码(.scala)会被编译成Java字节码(.class),然后运行于JVM之上,并可以调用现有的 Java 类库,实现两种语言的无缝对接。[案例演示]
3) scala 单作为一门语言来看, 非常的简洁高效 (三元运算, ++ , --)
4) Scala 在设计时,马丁·奥德斯基 是参考了 Java 的设计思想,可以说 Scala 是源于 java,同时 马丁·奥德斯基 也加入了自己的思想,将函数式编程语言的特点融合到 JAVA 中, 因此,对于学习过 Java 的同学,只要在学习 Scala 的过程中,搞清楚 Scala 和 java 相同点和不同点,就可以快速的掌握 Scala 这门语言
5) 快速有效掌握 Scala 的三点建议 [1. 学习 **scala** 的特有的语法 **2.** 区别 **scala** 和 **Java 3.** 如何规 范使用 **scala**]
1.2java、scala和jvm的关系图
2.变量
2.1定义
var | val 变量名 [: 变量类型] = 变量值
- 声明变量时,类型可以省略(编译器自动推导,即类型推导)
- 类型确定后,就不能修改,说明 Scala 是强数据类型语言.
- 在声明/定义一个变量时,可以使用 var 或者 val 来修饰, var 修饰的变量可改变,val 修饰的变量不可改
- val修饰的变量在编译后,等同于加上final
- var 修饰的对象引用可以改变,val 修饰的则不可改变,但对象的状态(值)却是可以改变的。(比 如: 自定义对象、数组、集合等等) [分析 val 好处]
- 变量声明时,需要初始值。
2.2数据类型
- Scala 与 Java 有着相同的数据类型,在 Scala 中数据类型都是对象,也就是说 scala 没有 java 中的原生类型
- Scala 数据类型分为两大类 AnyVal(值类型) 和AnyRef(引用类型), 注意:不管是 AnyVal 还 是 AnyRef 都是对象。[案例演示 Int , Char]
- 相对于 java 的类型系统,scala 要复杂些!也正是这复杂多变的类型系统才让面向对象编程和函 数式编程完美的融合在了一起
说明
- 在 scala 中有一个根类型 Any ,他是所有类的父类.
- scala中一切皆为对象,分为两大类AnyVal(值类型),AnyRef(引用类型),他们都是Any子类.
- Null 类型是 scala 的特别类型,它只有一个值 null, 他是 bottom class ,是 所有 AnyRef 类型的子类
- Nothing类型也是bottomclass,他是所有类的子类,在开发中通常可以将Nothing类型的值返回给任意变量或者函数, 这里抛出异常使用很多.
- 在 scala 中仍然遵守,低精度的值,向高精度的值自动转换(implicit conversion) 隐式转换.
2.3关于Null、Unit、Nothing
- Null类只有一个实例对象,null,类似于Java中的null引用。null可以赋值给任意引用类型 (AnyRef),但是不能赋值给值类型(AnyVal: 比如 Int, Float, Char, Boolean, Long, Double, Byte, Short)
- Unit类型用来标识过程,也就是没有明确返回值的函数。由此可见,Unit类似于Java里的void。 Unit 只有一个实例,(),这个实例也没有实质的意义
- Nothing,可以作为没有正常返回值的方法的返回类型,非常直观的告诉你这个方法不会正常返 回,而且由于 Nothing 是其他任意类型的子类,他还能跟要求返回值的方法兼容。
2.4值类型转换
自动类型转换细节说明
1) 有多种类型的数据混合运算时,系统首先自动将所有数据转换成容量最大的那种数据类型,然后再进行计算。 5.6 + 10 = 》double
2) 当我们把精度(容量)大 的数据类型赋值给精度(容量)小 的数据类型时,就会报错,反之就会进行自动类型转换
3) (byte, short) 和 char 之间不会相互自动转换。
4) byte,short,char 他们三者可以计算,在计算时首先转换为 int 类型。
5) 自动提升原则: 表达式结果的类型自动提升为 操作数中最大的类型
3.流程控制
3.1顺序控制
程序从上到下逐行执行,中间没有任何判断和跳转
3.2分支控制
if (条件表达式 1) {
执行代码块 1
} else if (条件表达式 2) {
执行代码块 2
} else {
执行代码块 n
}
3.3switch 分支结构
后面详细讲解
3.4for 循环控制
Scala 也为 for 循环这一常见的控制结构提供了非常多的特性,这些 for 循环的特性被称为 **for** 推导式(for comprehension)或 **for** 表达式(for expression)
3.4.1范围数据循环方式 1
object ForDemo01 {
def main(args: Array[String]): Unit = {
//输出 10 句 "hello,尚硅谷!"
val start = 1
val end = 10
//说明
//1. start 从哪个数开始循环 //2. to 是关键字
//3. end 循环结束的值
//4. start to end 表示前后闭合
for (i <- start to end) {
println("你好,world" + i)
}
//说明 for 这种推导时,也可以直接对集合进行遍历 var list = List("hello", 10, 30, "tom")
for (item <- list) {
println("item=" + item) }
}
}
3.4.2范围数据循环方式 2
for(i <- 1 until 3) {
print(i + " ") }
3.4.3循环守卫
循环守卫,即循环保护式(也称条件判断式,守卫)。保护式为 true 则进入循环体内部,为 false
则跳过,类似于 continue
for(i <- 1 to 3 if i != 2) {
print(i + " ")
}
3.4.4引入变量
for(i <- 1 to 3; j = 4 - i) {
print(j + " ")
}
// 没有关键字,所以范围后一定要加;来隔断逻辑 上面的代码等价
for ( i <- 1 to 3) {
valj=4 –i
print(j+"")
}
3.4.5嵌套循环
for(i <- 1 to 3; j <- 1 to 3) {
println(" i =" + i + " j = " + j)
}
// 没有关键字,所以范围后一定要加;来隔断逻辑 上面的代码等价
for ( i <- 1 to 3) {
for ( j <- 1to 3){
println(i + " " + j + " ")
}
}
3.4.6循环返回值
val res = for(i <- 1 to 10) yield i
println(res)
// 将遍历过程中处理的结果返回到一个新 Vector 集合中,使用 yield 关键字
3.4.7使用花括号{}代替小括号()
for(i<-1to3;j= i*2){
println(" i= " + i + " j= " + j)
}
// 可以写成
for{
i <- 1 to 3
j = i * 2} {
println(" i= " + i + " j= " + j)
}
- {}和()对于 for 表达式来说都可以
- for 推导式有一个不成文的约定:当 for 推导式仅包含单一表达式时使用圆括号,当其包含多个表达式时使用大括号
- 当使用{} 来换行写表达式时,分号就不用写了
说明:
1) scala 的 for 循环形式和 java 是较大差异,这点请同学们注意,但是基本的原理还是一样的
2) scala 的 for 循环的步长如何控制! [for(i <- Range(1,3,2)]
3.5while循环控制
循环变量初始化
while (循环条件) {
循环体(语句) 循环变量迭代
}
- 循环条件是返回一个布尔值的表达式
- while循环是先判断再执行语句
- 与 If 语句不同,While 语句本身没有值,即整个 While 语句的结果是 Unit 类型的()
- 因为 while 中没有返回值,所以当要用该语句来计算并返回结果时,就不可避免的使用变量 ,而变量需要声明在 while 循环的外部,那么就等同于循环的内部对外部的变量造成了影响,所以不推荐使 用,而是推荐使用 for 循环。
3.6do..while 循环控制
do {
循环体(语句) 循环变量迭代
} while(循环条件)
- 循环条件是返回一个布尔值的表达式
- do..while循环是先执行,再判断
- 和 while 一样,因为 do...while 中没有返回值
3.7多重循环控制
- 将一个循环放在另一个循环体内,就形成了嵌套循环。其中,for ,while ,do...while 均可以作为 外层循环和内层循环。【建议一般使用两层,最多不要超过 3 层】
- 实质上,嵌套循环就是把内层循环当成外层循环的循环体。当只有内层循环的循环条件为 false 时,才会完全跳出内层循环,才可结束外层的当次循环,开始下一次的循环。
- 设外层循环次数为 m 次,内层为 n 次, 则内层循环体实际上需要执行 m*n=mn 次。
3.8while 循环的中断
Scala 内置控制结构特地去掉了 break 和 continue,是为了更好的适应函数化编程,推荐使用函数式的风格解决 break 和 contine 的功能,而不是一个关键字。
//breakable()函数
//说明
//1. breakable 是一个高阶函数:可以接收函数的函数就是高阶函数(后面详解
breakable {
while (n <= 20) {
n += 1
println("n=" + n) if (n == 18) {
//中断 while
//说明
//1. 在 scala 中使用函数式的 break 函数中断循环
//2. def break(): Nothing = { throw breakException }
break()
}
}
4函数式编程-基础篇
4.1几个概念
在学习 Scala 中将方法、函数、函数式编程和面向对象编程明确一下:
- 在 scala 中,方法和函数几乎可以等同(比如他们的定义、使用、运行机制都一样的),只是函数 的使用方式更加的灵活多样。
- 函数式编程是从编程方式(范式)的角度来谈的,可以这样理解:函数式编程把函数当做一等公 民,充分利用函数、 支持的函数的多种使用方式。
- 比如:在 Scala 当中,函数是一等公民,像变量一样,既可以作为函数的参数使用,也可以将函数赋值给一个 变量. ,函数的创建不用依赖于类或者对象,而在 Java 当中,函数的创建则要依赖于类、抽象类或者 接口.
- 面向对象编程是以对象为基础的编程方式
- 在 scala 中函数式编程和面向对象编程融合在一起了
在学习 Scala 中将方法、函数、函数式编程和面向对象编程关系分析图:
4.2函数式编程的小结
- "函数式编程"是一种"编程范式"(programming paradigm)
- 它属于"结构化编程"的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用
- 函数式编程中,将函数也当做数据类型,因此可以接受函数当作输入(参数)和输出(返回值)
- 函数式编程中,最重要的就是函数
4.3函数的定义
def 函数名 ([参数名: 参数类型], ...)[[: 返回值类型] =] {
语句...
return 返回值
}
- 函数声明关键字为 def (definition)
- [参数名: 参数类型], ...:表示函数的输入(就是参数列表), 可以没有。 如果有,多个参数使用 逗号间隔
- 函数中的语句:表示为了实现某一功能代码块
- 函数可以有返回值,也可以没有
返回值形式 1: 全写,正常行驶
返回值形式 2: () = {xxx} 表示返回类型不确定,使用推导类型
返回值形式 3: (xxx){xxx} 表示没有返回值,return 不生效 - 如果没有 return ,默认以执行到最后一行的结果作为返回值
4.4 函数调用机制
4.4.1调用过程
4.4.2函数递归调用的重要的规则和小结
函数递归需要遵守的重要原则(总结):
- 程序执行一个函数时,就创建一个新的受保护的独立空间(新函数栈)
- 函数的局部变量是独立的,不会相互影响
- 递归必须向退出递归的条件逼近,否则就是无限递归,死龟了:)
- 当一个函数执行完毕,或者遇到 return,就会返回,遵守谁调用,就将结果返回给谁。
4.4.3 函数注意事项和细节讨论
- 函数的形参列表可以是多个, 如果函数没有形参,调用时 可以不带()
- 形参列表和返回值列表的数据类型可以是值类型和引用类型
- Scala中的函数可以根据函数体最后一行代码自行推断函数返回值类型。那么在这种情况下, return 关键字可以省略
- 因为 Scala 可以自行推断,所以在省略 return 关键字的场合,返回值类型也可以省略
- 如果函数明确使用 return 关键字,那么函数返回就不能使用自行推断了,这时要明确写成 : 返回类型 = ,当然如果你什么都不写,即使有 return 返回值为()
- 如果函数明确声明无返回值(声明 Unit),那么函数体中即使使用 return 关键字也不会有返回 值
- 如果明确函数无返回值或不确定返回值类型,那么返回值类型可以省略(或声明为 Any
- Scala语法中任何的语法结构都可以嵌套其他语法结构(灵活),即:函数中可以再声明/定义函数, 类中可以再声明类 ,方法中可以再声明/定义方法
- Scala函数的形参,在声明参数时,直接赋初始值(默认值),这时调用函数时,如果没有指定实参,则会使用默认值。如果指定了实参,则实参会覆盖默认值。
- 如果函数存在多个参数,每一个参数都可以设定默认值,那么这个时候,传递的参数到底是覆 盖默认值,还是赋值给没有默认值的参数,就不确定了(默认按照声明顺序[从左到右])。在这种情况下, 可以采用带名参数
- 递归函数未执行之前是无法推断出来结果类型,在使用时必须有明确的返回值类型
- Scala函数支持可变参数
1. args 是集合, 通过 for 循环 可以访问到各个值。
2. 案例演示: 编写一个函数 sum ,可以求出 1 到多个 int 的和
3. 可变参数需要写在形参列表的最后。
4.4.4过程
将函数的返回类型为Unit的函数称之为过程(procedure),如果明确函数没有返回值,那么等号可以省略
1) 注意区分: 如果函数声明时没有返回值类型,但是有 = 号,可以进行类型推断最后一行代码。 这时这个函数实际是有返回值的,该函数并不是过程。(这点在讲解函数细节的时候讲过的.)
2) 开发工具的自动代码补全功能,虽然会自动加上 Unit,但是考虑到 Scala 语言的简单,灵活, 最好不加.
4.5惰性函数
当函数返回值被声明为 lazy 时,函数的执行将被推迟,直到我们首次对此取值,该函数才会执行。
这种函数我们称之为惰性函数,在 Java 的某些框架代码中称之为懒加载(延迟加载)。
object LazyDemo01 {
def main(args: Array[String]): Unit = {
lazy val res = sum(10, 20)
println("-----------------")
println("res=" + res) //在要使用 res 前,才执行
}
//sum 函数,返回和
def sum(n1: Int, n2: Int): Int = {
println("sum() 执行了..") //输出一句话
return n1 + n2
}
}
1) lazy 不能修饰 var 类型的变量
2) 不但是 在调用函数时,加了 lazy ,会导致函数的执行被推迟,我们在声明一个变量时,如果给 声明了 **lazy ,**那么变量值得分配也会推迟。 比如 lazy val i = 10
4.6 异常
Scala提供try和catch块来处理异常。try块用于包含可能出错的代码。catch块用于处理try块中发 生的异常。可以根据需要在程序中有任意数量的 try...catch 块。
语法处理上和 Java 类似,但是又不尽相同
4.6.1Java 异常处理的注意点.
- java语言按照try—catch-catch...—finally的方式来处理异常
- 不管有没有异常捕获,都会执行 **finally**, 因此通常可以在 finally 代码块中释放资源
- 可以有多个 catch,分别捕获对应的异常,这时需要把范围小的异常类写在前面,把范围大的异
常类写在后面,否则编译错误。会提示 "Exception 'java.lang.xxxxxx' has already been caught"
4.6.2Scala 异常处理小结
- 我们将可疑代码封装在 **try** 块中。 在 try 块之后使用了一个 catch 处理程序来捕获异常。如果发 生任何异常,catch 处理程序将处理它,程序将不会异常终止。
- Scala的异常的工作机制和Java一样,但是**Scala**没有“**checked(**编译期**)**”异常,即Scala没有 编译异常这个概念,异常都是在运行的时候捕获处理。
- 用 throw关键字,抛出一个异常对象。所有异常都是 Throwable 的子类型。throw 表达式是有类 型的,就是 Nothing,因为 Nothing 是所有类型的子类型,所以 throw 表达式可以用在需要类型的地方
- 在 Scala 里,借用了模式匹配的思想来做异常的匹配,因此,在 catch 的代码里,是一系列 case 子句来匹配异常。【前面案例可以看出这个特点**,** 模式匹配我们后面详解】,当匹配上后 => 有多条 语句可以换行写,类似 java 的 switch case x: 代码块..
- 异常捕捉的机制与其他语言中一样,如果有异常发生,catch 子句是按次序捕捉的。因此,在 catch子句中,越具体的异常越要靠前,越普遍的异常越靠后,如果把越普遍的异常写在前,把具体异常写在后,在 **scala** 中也不会报错,但这样是非常不好的编程风格。
- finally子句用于执行不管是正常处理还是有异常发生时都需要执行的步骤,一般用于对象的清理工作,这点和 Java 一样。
- Scala提供了throws关键字来声明异常。可以使用方法定义声明异常。它向调用者函数提供了此方法可能引发此异常的信息。 它有助于调用函数处理并将该代码包含在 try-catch 块中,以避免程序 异常终止。在 scala 中,可以使用 throws 注释来声明异常
5.面向对象编程-基础部分
5.1类和对象
- Java是面向对象的编程语言,由于历史原因,Java中还存在着非面向对象的内容:基本类型, null,静态方法等。
- Scala语言来自于Java,所以天生就是面向对象的语言,而且Scala是纯粹的面向对象的语言, 即在 Scala 中,一切皆为对象。
- 在面向对象的学习过程中可以对比着 Java 语言学习
5.1.1类和对象的区别和联系
- 类是抽象的,概念的,代表一类事物,比如人类,猫类..
- 对象是具体的,实际的,代表一个具体事物
- 类是对象的模板,对象是类的一个个体,对应一个实例
- Scala 中类和对象的区别和联系 和 Java 是一样的。
5.1.2 如何定义类
基本语法
[修饰符] class 类名 {
类体
}
定义类的注意事项
- scala语法中,类并不声明为public,所有这些类都具有公有可见性(即默认就是public),[修饰符在后面再详解].
- 一个 Scala 源文件可以包含多个类.,而且默认都是 public
5.1.3属性
属性是类的一个组成部分,一般是值数据类型,也可是引用类型。比如我们前面定义猫类 的 age 就是属性
5.1.4属性/成员变量
注意事项和细节说明
1) 属性的定义语法同变量,示例:[访问修饰符] var 属性名称 [:类型] = 属性值
2) 属性的定义类型可以为任意类型,包含值类型或引用类型[案例演示]
3) Scala中声明一个属性,必须显示的初始化,然后根据初始化数据的类型自动推断,属性类型可以省略(这点和 Java 不同)。
4) 如果赋值为 null,则一定要加类型,因为不加类型, 那么该属性的类型就是 Null 类型.
5) 如果在定义属性时,暂时不赋值,也可以使用符号_(下划线),让系统分配默认值.
5.1.5属性的高级部分
说明:属性的高级部分和构造器(构造方法/函数) 相关,我们把属性高级部分放到构造器那里讲解。
5.1.6如何创建对象
val | var 对象名 [:类型] = new 类型()
1) 如果我们不希望改变对象的引用(即:内存地址), 应该声明为 val 性质的,否则声明为 var, scala设计者推荐使用 val ,因为一般来说,在程序中,我们只是改变对象属性的值,而不是改变对象的引用
2) scala在声明对象变量时,可以根据创建对象的类型自动推断,所以类型声明可以省略,但当类型和后面 new对象类型有继承关系即多态时,就必须写了
5.2方法
Scala 中的方法其实就是函数,声明规则请参考函数式编程中的函数声明。
def 方法名(参数列表) [:返回值类型] = {
方法体
}
5.3构造器
[修饰符] 方法名(参数列表){ 构造方法体}
class 类名(形参列表) { // 类体
def this(形参列表) { }
def this(形参列表) { }
// 主构造器
// 辅助构造器 //辅助构造器可以有多个...
}
- Scala构造器作用是完成对新对象的初始化,构造器没有返回值。
- 主构造器的声明直接放置于类名之后 [反编译]
- 主构造器会执行类定义中的所有语句,这里可以体会到 Scala 的函数式编程和面向对象编程融 合在一起,即:构造器也是方法(函数),传递参数和使用方法和前面的函数部分内容没有区别
- 如果主构造器无参数,小括号可省略,构建对象时调用的构造方法的小括号也可以省略
- 辅助构造器名称为 this(这个和 Java 是不一样的),多个辅助构造器通过不同参数列表进行区 分, 在底层就是 f 构造器重载
- 如果想让主构造器变成私有的,可以在()之前加上 private,这样用户只能通过辅助构造器来构 造对象了
- 辅助构造器的声明不能和主构造器的声明一致,会发生错误(即构造器名重复)
5.4构造器参数
5.4.1说明
- Scala类的主构造器的形参未用任何修饰符修饰,那么这个参数是局部变量。
- 如果参数使用val关键字声明,那么Scala会将参数作为类的私有的只读属性使用【案例+反编 译】
- 如果参数使用var关键字声明,那么那么 Scala 会将参数作为类的成员属性使用,并会提供属性 对应的 xxx()[类似 getter]/xxx_$eq()[类似 setter]方法,即这时的成员属性是私有的,但是可读写。
5.4.2Bean 属性
JavaBeans 规范定义了 Java 的属性是像 getXxx()和 setXxx()的方法。许多 Java 工具(框架) 都依赖这个命名习惯。为了 Java 的互操作性。将 Scala 字段加@BeanProperty 时,这样会自动生成规范 的 setXxx/getXxx 方法。这时可以使用 对象.setXxx() 和 对象.getXxx() 来调用属性。
注意:给某个属性加入@BeanPropetry注解后,会生成getXXX和setXXX方法,并且对原来底层自动生成类似 xxx(),xxx_$eq()方法,没有冲突,二者可以共存
6.集合
6.1集合特点
6.1.1scala集合基本介绍
- scala同时支持不可变和可变集合,不可变集合可以安全的并发访问,两个主要的包:
不可变集合:scala.collection.immutable
可变集合:scala.collection.mutable
- scala默认采用不可变集合,对于几乎所有的集合类,scala都同时提供了可变和不可变的版本
- scala的集合有三大类:序列Seq、集Set、映射Map,所有的集合都扩展自Iterable特质,
6.1.2可变集合和不可变集合
- 不可变集合:scala不可变集合,就是这个集合本身不能动态变化。类似于java的数组,是不可以动态增长的
- 可变集合:就是这个集合本身可以动态变化(比如ArrayList,是可以动态增长的)
6.2不可变集合继承层次一览图
- set、map是java中也有的集合
- seq是java没有的,我们发现List归属到Seq了,因此这里的List和java不是一个概念
- 我们前面的for循环有一个1 to 3,就是IndexSeq下的Vector
- String也是属于IndexSeq
- 我们发现经典的数据结构比Queue和Stack被归属到LinearSeq
- scala中的map体系也有一个SortedMap,说明scala的Map可以支持排序
- IndexSeq和LinearSeq的区别是通过索引来查找和定位,因此速度快,比如String就是一个索引集合,通过索引即可定位LineaSeq是线性的,即有头尾的概念
6.3可变集合继承层次一览图
- 在可变集合中比不可变集合更加丰富
- 在 Seq 集合中, 增加了 Buffer 集合,将来开发中,我们常用的有 ArrayBuffer 和 ListBuffer
- 如果涉及到线程安全可以选择使用 syn.. 开头的集合
- 其它的说明参考不可变集合
6.4数组
6.4.1定长数组
// 方法一
//这里的数组等同于 Java 中的数组,中括号的类型就是数组的类型
val arr1 = new Array[Int](10)
//赋值,集合元素采用小括号访问
arr1(1) = 7
// 方法二
//在定义数组时,直接赋值
//使用 apply 方法创建数组对象
val arr1 = Array(1, 2)
6.4.2变长数组
val arr2 = ArrayBuffer[Int]()
//追加值/元素
arr2.append(7)
//重新赋值
arr2(0) = 7
1) ArrayBuffer是变长数组,类似java的ArrayList
2) val arr2 = ArrayBuffer[Int]() 也是使用的 apply 方法构建对象
3) def append(elems: A*) { appendAll(elems) } 接收的是可变参数.
4) 每 append 一次,arr 在底层会重新分配空间,进行扩容,arr2 的内存地址会发生变化,也就成 为新的 ArrayBuffer
6.4.3数组-Scala 数组与 Java 的 List 的互转
6.5元组tuple
元组也是可以理解为一个容器,可以存放各种相同或不同类型的数据。
说的简单点,就是将多个无关的数据封装为一个整体,称为元组, 最多的特点灵活,对数据没有过 多的约束
注意:元组中最大只能有 22 个元素
6.6List
Scala 中的 List 和 Java List 不一样,在 Java 中 List 是一个接口,真正存放数据是 ArrayList,而 Scala 的 List 可以直接存放数据,就是一个 object
默认情况下 Scala 的 List 是不可变的,List 属于序列 Seq
val List = scala.collection.immutable.List object List extends SeqFactory[List]
6.6.1创建
- List默认为不可变的集合
- List 在 scala 包对象声明的,因此不需要引入其它包也可以使用 val List = scala.collection.immutable.List
- List 中可以放任何数据类型,比如 arr1 的类型为 List[Any]
- 如果希望得到一个空列表,可以使用 Nil 对象, 在 scala 包对象声明的,因此不需要引入其它包也可以使用val Nil = scala.collection.immutable.Nil
6.6.2元素的追加
向列表中增加元素, 会返回新的列表/集合对象。注意:Scala 中 List 元素的追加形式非常独特,和 Java 不一样。
需注意以下几点
- 符号::表示向集合中 新建集合添加元素。
- 运算时,集合对象一定要放置在最右边,
- 运算规则,从右向左。
- ::: 运算符是将集合中的每一个元素加入到集合中去
6.7ListBuffer
ListBuffer 是可变的 list 集合,可以添加,删除元素,ListBuffer 属于序列 //追一下继承关系即可
Seq var listBuffer = ListBuffer(1,2)
6.8队列
1) 队列是一个有序列表,在底层可以用数组或是链表来实现。
2) 其输入和输出要遵循先入先出的原则。即:先存入队列的数据,要先取出。后存入的要后取
3) 在 Scala 中,由设计者直接给我们提供队列类型 Queue 使用。
4) 在 scala 中, 有 scala.collection.mutable.Queue 和 scala.collection.immutable.Queue , 一般来说,我们在开发中通常使用可变集合中的队列
6.9Map
1) Scala中的Map和Java类似,也是一个散列表,它存储的内容也是键值对(key-value)映射,Scala 中不可变的 Map 是有序的,可变的 Map 是无序的。
2) Scala中,有可变Map (scala.collection.mutable.Map) 和 不 可 变 Map(scala.collection.immutable.Map)