一、Scala基础语法

===

(一) 变量、类型、操作符

1.变量申明

●Java中:

//数据类型 变量名 = 值;
final int b = 2;
b = 23; //错误!!! final修饰的变量不可变
int a = 1;
a = 22;

●在Scala中:

//val/var 变量名:变量类型 = 变量值
val a:Int = 1
a =2 //错误!!!! val修饰的变量不可以被重新赋值,类似于Java中的final
var b:Int = 1
b = 2

●说明

var声明的变量可以重新赋值

val声明的变量不可以重新赋值,或称之为不可变变量/只读变量。相当于java里用final修饰的变量

●注意:

Scala中变量声明类型可以省略,解析器会根据值进行推断

Scala中语句最后不需要添加分号

val和var声明变量时都必须初始化

为了减少可变性引起的bug,应该尽可能地使用不可变变量val。(推荐使用val)

如果想在变量名、类名等定义中使用语法关键字(保留字),可以配合反引号:

val `val` = 123    //(符号为键盘上Esc下面的键)

●Type关键字

Scala 里可以通过type 关键字来声明类型。

type 相当于声明一个类型别名:

// 把String 类型用S 代替
type S = String
val name: S = "bigdata"
println (name)

●懒值

应用场景

​ 当val被声明为lazy时,初始化将被推迟,只有当这个变量真正被使用到的时候,变量的赋值代码才会真正的执行

​ lazy适用于初始化开销较大的场景

●代码演示

package com.flyingAfish.baseTest

object VariableDemo {
def main(args: Array[String]): Unit = {
val name:String = "fizz"
//name = "jack ma" //错误,val修饰的变量不能被重新赋值
var money:Int = 8888
money = 565//var修饰的变量可以重新赋值 val age = 18 //:Int 类型可以省略,编译器会自动推断age的类型
//age = "fizz" //错误,因为scala是强类型 type str = String //type关键字可以给类型起别名
val animal:str = "fish" //当val被声明为lazy时,初始化将被推迟,只有当这个变量真正被使用到的时候,变量的赋值代码才会真正的执行
//lazy适用于初始化开销较大的场景
val msg1 = init()
println("我是按顺序执行的")
println(msg1)
println("===============")
lazy val msg2 = init()
println("我先于init方法执行")
println(msg2)
} //定义一个方法,输出一句话并返回一个字符串
def init() ={
println("init方法执行了")
"msg"
}
} /* init方法执行了
我是按顺序执行的
msg
===============
我先于init方法执行
init方法执行了
msg
*/

2.字符串

​ scala提供多种定义字符串的方式,我们可以根据需要来选择最方便的定义方式。

●双引号

val/var 变量名 = "字符串"

●三引号

​ 如果有大段的文本需要保存,就可以使用三引号来定义字符串。例如:保存一大段的SQL语句。三个引号中间的所有字符串都将作为字符串的值。

val/var 变量名 = """字符串1字符串2"""

●使用插值表达式

​ scala中,可以使用插值表达式来定义字符串,有效避免大量字符串的拼接。

val/var 变量名 = s"${变量/表达式}字符串"
val/var 变量名 = s"""${变量/表达式}字符串"""

●代码演示

package com.flyingAfish.baseTest

object StringDemo {
def main(args: Array[String]): Unit = {
val name = "fizz"
val sql =
"""
|select * // | 竖条为编译器自动添加
|from table
|where name = fizz
""".stripMargin //.stripMargin 编译器自动添加
val sql2 =
s""" //s 为编译器自动添加
|select *
|from table
|where name = ${name}
""".stripMargin println(name)
println(sql)
println(sql2)
}
}
/*
fizz select *
from table
where name = fizz select *
from table
where name = fizz
*/

3.数据类型

●数值类型

Scala和Java一样,有多种数值类型Byte、Char、Short、Int、Long、Float、Double类型和1个Boolean类型。

Boolean true 或者 false
Byte 8位, 有符号
Short 16位, 有符号
Int 32位, 有符号
Long 64位, 有符号
Char 16位, 无符号
Float 32位, 单精度浮点数
Double 64位, 双精度浮点数
String 其实就是由Char数组组成

●继承体系

![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml19704\wps2.png)

●Any

在scala中,所有的类,包括值类型,都最终继承自一个统一的根类型Any,Any类是根节点

Any中定义了isInstanceOf、asInstanceOf方法,以及哈希方法等。AnyVal和AnyRef都扩展自Any类。

​ isInstanceOf:是否继承自某类

​ asInstanceOf:强制类型转换

●AnyVal-所有值类型的基类,所有的值都是类类型都是AnyVal的子类

- scala.Double

- scala.Float

- scala.Long

- scala.Int

- scala.Char

- scala.Short

- scala.Byte

上面是数字类型。

还包括scala.Unit 和 scala.Boolean 是非数字类型。

●AnyRef-是所有引用类型的基类。

​ 除了值类型,所有其他类型都继承自AnyRef

●Null

​ 是所有引用类型的子类型,Null类只有一个实例对象,null,类似于Java中的null引用。null可以赋值给任意引用类型,但是不能赋值给值类型

●Nothing

是所有类型的子类型。Nothing类型没有实例。它对于泛型结构是有用处的,举例:

空列表Nil的类型是List[Nothing],它是List[T]的子类型,T可以是任何类。

Nothing可以作为没有正常返回值的方法的返回类型,非常直观的告诉你这个方法不会正常返回,而且由于Nothing是其他任意类型的子类,他还能跟要求返回值的方法兼容。

●Unit

用来标识过程,也就是没有明确返回值的函数。

由此可见,Unit类似于Java里的void。Unit只有一个对象实例(),这个实例也没有实质的意义。

●注意

1.Scala并不刻意区分基本类型 和 引用类型,所以这些类型都是对象,可以调用相对应的方法。

2.每一种数值类型都有对应的Rich类型,如RichInt、RichChar等,为基本类型提供了更多的有用操作。(重要

3.String直接使用的是java.lang.String类,另外在scala.collection.immutable.StringOps中还定义了更多的操作。在需要时String能隐式转换为StringOps,因此不需要任何额外的操作,String就可以使用这些方法。

4.操作符

Scala中的+ - * / %等操作符的作用与Java一样,位操作符 & | ^ >> <<也一样。

●注意:

1.Scala中的操作符实际上是方法

2.Scala中没有++、--操作符,需要通过+=、-=来实现同样的效果(因为++ -- 前置后置容易混淆)

3.+ - * / %是方法,那么就可以进行操作符重载,完成特殊的运算(也就是自己在类中定义+ - * / %方法表示特殊的运算)

●高级:

1)中置操作符,

//A操作符B 等同于 A.操作符(B)
val a = 1
val b = 2
var c = a + b
var d = a.+(b) //等同与上式

2)后置操作符,

​ A操作符 等同于 A.操作符,如果操作符定义的时候不带()则调用时不能加括号

math.random

3)前置操作符,

​ +、-、!、~等操作符 A等同于 A.unary_操作符。

var b = true
b = !b
b = b.unary_! //等同与上式

4)赋值操作符,

​ A操作符=B 等同于 A=A操作符B

a += 1
a = a + 1 //等同与上式

●代码演示

package com.flyingAfish.baseTest

object OperatorDemo {
def main(args: Array[String]): Unit = {
var a = 1
var b = 2
val result = a + b
println(result)//3
val result2 = a.+(b) //在Scala中运算符其实是方法
println(result2)//3
//a++ //错误,在Scala中为了避免混淆,不支持++ --
a += 1 //a = a + 1
println(a)//2
}

(二)循环判断

1.块表达式

定义变量时可以使用 {} 包含一系列表达式,其中{}块的最后一个表达式的值就是整个块表达式的值。

●代码演示

package com.flyingAfish.baseTest

object E_BlockDemo {
def main(args: Array[String]): Unit = {
var a = 1
var b =2
var c = {
a = a + b
b = a + b
var i = a + b
i //注意:{}块表达式的最后一行是整个表达式的值
}
println(c)//8
}
}

2.条件表达式

Scala条件表达式的语法和Java一样,只是更加简洁,且Scala中if else表达式是有返回值的

●注意:

Scala中没有三元表达式

如果if或者else返回的类型不一样,就返回Any类型

对于没有返回值的,使用Unit,写做(),相当于java中的void

●代码演示

package com.flyingAfish.baseTest

object ConditionDemo {
def main(args: Array[String]): Unit = {
val sex1 = "male"
val sex2 = "female" //if表达式有返回值
val result1:String = if(sex1 == "male"){
"男"
}else{
"女"
}
println(result1) val result2:String = if(sex1 == "male") "男" else "女"
println(result2) //如果返回值类型不一致,返回Any
val result3:Any = if(sex2 == "male"){
"男"
}else{
0
}
println(result3) //()表示没有返回值,即Unit,相当于Java中的void
val result4:Unit = if(sex2 == "male"){
println("男")
}else{
println("女")
}
println(result4)//()
}
}

3.循环表达式

在scala中,可以使用for循环和while循环,但一般推荐使用for表达式,因为for表达式语法更简洁

●简单for循环:

​ for (变量 <- 表达式/数组/集合) {循环体}

for(i <- 1 to 10){println(i)} //循环打印1~10

●嵌套for循环

​ for (变量1 <- 表达式/数组/集合; 变量2 <- 表达式/数组/集合) {循环体}

for(i <- 1 to 9; j <- 1 to 9){
if(i >= j ) print(s"${j} * ${i} = ${j*i}")
if(j == 9) println()
}

●守卫

​ for表达式中,可以添加if判断语句,这个if判断就称之为守卫。我们可以使用守卫让for表达式更简洁。

​ for(i <- 表达式/数组/集合 if 表达式) {循环体}

for(i <- 1 to 10 if i % 3 == 0) println(i) //3,6,9

●for推导式(有返回值)

​ 在for循环体中,可以使用yield表达式构建出一个集合,我们把使用yield的for表达式称之为推导式

​ 即可以使用for推导式生成一个新的集合(一组数据)

//该for表达式会构建出一个集合
val res = for(i <- 1 to 10) yield i * 10 //10,20,30,40...

●注意:

​ while、for语句本身没有值,即整个while语句的结果是Unit类型的()

var n = 1;
val result:unit = while(n <= 10){
n += 1
}
println(result)
println(n)

●代码演示

package com.flyingAfish.baseTest

object LoopDemo {
def main(args: Array[String]): Unit = {
//1 to 10 ===> [1,10]
val res1 = 1 to 10 //Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
//1 until 10 ===> [1,10)
val res2 = 1 until 10 //Range(1, 2, 3, 4, 5, 6, 7, 8, 9)
//1 to 10 ===> [1,10],步长为2
val res3 = 1 to 10 by 2 //Range(1, 3, 5, 7, 9)
println(res1)
println(res2)
println(res3) //1.简单for循环
for(i <- 1 to 10) println(i) println("===========分割线==========")
//2.嵌套for循环--传统写法
for(i <- 1 to 9){
for(j <- 1 to 9){
if(i >= j){
print(s"${j} * ${i} = ${j * i} \t")
}
}
println()
}
println("===========分割线==========")
//2.嵌套for循环--Scala骚气写法
for(i <- 1 to 9;j <- 1 to 9){
if(i >= j) print(s"${j} * ${i} = ${j * i} \t")
if(j == 9) println()
}
println("===========分割线==========")
//3.守卫
//需求打印1~10中3的倍数
for(i <- 1 to 10){
if(i % 3 == 0) println(i)
}
println("===========分割线==========")
for(i <- 1 to 10 if(i % 3 == 0)) println(i) println("===========分割线==========")
//4.for推导式
//需求把1~10中的每一个数扩大10倍形成一个新的集合
//使用yield关键字可以生成一个新的集合
val col = for(i <- 1 to 10) yield i * 10
println(col)//Vector(10, 20, 30, 40, 50, 60, 70, 80, 90, 100) println("===========分割线==========")
//5.注意:while循环没有返回值
var n =1
val result = while (n <= 100){
n += 1
n
}
println(n)//101
println(result)//()
}
}

(三)方法和函数

1.方法

def 方法名(参数名1: 参数类型1, 参数名2: 参数类型2) : 返回类型 = {方法体}

●语法细节

\1. 方法的返回值类型和return可以不写,编译器可以自动推断出来

\2. 对于递归方法必须指定返回类型

\3. 如果方法没有返回值,返回Unit类型(类似于void,也可以不写)

\4. 返回值类型有多种情况则返回Any

\5. 带有默认值参数的方法,调用时,可以给定新值,也可以使用默认值

\6. 可以通过参数名来指定传递给哪一个参数,这样传递参数时就可以不按照顺序传递

\7. 方法没有参数,调用时可以省略(),如果定义时()省略,调用时则必须省略

\8. 可变参数使用 变量名: 类型* (类似Java的...

●代码演示

package com.flyingAfish.baseTest

object MethodDemo {
def main(args: Array[String]): Unit = {
val result: Int = factorial(3)
println(result)//6
println(noReturnValue())//()
//val resutl2: Int = haveDefaultParam(b=2)//102
//val resutl3: Int = haveDefaultParam(a=1,b=2)//3
//val resutl4: Int = haveDefaultParam(1,2)//3
val resutl5: Int = haveDefaultParam(b=2,a=1)//3
//println(resutl2)
//println(resutl3)
//println(resutl4)
println(resutl5) noParam val sum: Int = multiParam(1,2,3,4,5)//15
println(sum)
} //def 方法名(参数名1:参数类型,参数名1:参数类型):返回值类型 = {方法体}
//1.方法的返回值类型和return可以不写,编译器可以自动推断出来
def omitReturnValue() ={
1
} //2.对于递归方法,必须指定返回类型
//需求:求n的阶乘 ==> 10的阶乘=1*2*3...*10 == 10 * 9 * 8 .....
def factorial(n:Int):Int = {
if (n == 1){
1
}else{
n * factorial(n-1)
}
} //3.如果方法没有返回值,返回Unit类型(类似于void,也可以不写)
def noReturnValue():Unit={
println("m3")
}
//4.返回值类型有多种情况则返回Any或者不写
val sex = "male"
def multiReturnValue():Any={
if (sex == "male"){
"男"
}else{
0
}
}
//5.带有默认值参数的方法,调用时,可以给定新值,也可以使用默认值
//6.可以通过参数名来指定传递给哪一个参数,这样传递参数时就可以不按照顺序传递
def haveDefaultParam(a:Int=100,b:Int):Int={
println("a="+a)
println("b="+b)
a + b
}
//7.方法没有参数,调用时可以省略(),如果定义时()省略,调用时则必须省略
def noParam={
println("m7")
}
//8.可变参使用 变量名:类型* (类似Java的...)
//定义了一个方法可以传递多个int值,并返回他们的和
def multiParam(args:Int*):Int={
var sum = 0
for (i <- args){
sum +=i
}
sum
}
}

2.函数

●完整语法:

​ val函数名称 :(参数类型)=>函数返回值类型 = (参数名称:参数类型)=>函数体

val sum:(Int,Int)=>Int = (a:Int,b:Int)=>{a + b}

●简写语法:

​ val函数名称 = (参数名称:参数类型) => 函数体

val max = (a:Int,b:Int)=>{
if(a > b) a
else b
}

●符号解释

​ = 表示将右边的函数 赋给 左边的变量

​ => 左面表示输入参数名称和类型,右边表示函数的实现和返回值类型

3.方法和函数的区别

●方法:

​ 和之前学习Java时理解的方法一样,是封装了完成某些功能的代码块,所属于某一个类或对象

●函数:

​ 在Scala中,函数是头等公民,函数是一个对象,那么既然是对象的话,函数就可以赋值给变量 或者 当作参数被传递,还可以 使用函数打点调用方法

​ Scala中函数继承自FuctionN,带有一个参数的函数的类型是function1,带有两个是function2,以此类推

●证明函数是对象

●函数是对象,可以打点调方法

package com.flyingAfish.baseTest

object FunctionDemo {
def main(args: Array[String]): Unit = {
//val函数名称 = (参数名称:参数类型) => 函数体
val add1 = (a:Int) => {a }
val add2 = (a:Int,b:Int) => {a + b}
val add3: (Int, Int, Int) => Int = (a:Int, b:Int, c:Int) => {a + b + c}
println(add1)//<function1>
println(add2)//<function2>
println(add3)//<function3> //结论:函数是对象,有N个参数打印的时候就是functionN
val str: String = add1.toString()//函数是对象,所以可以调用方法
println(str)//<function1> //函数一般用法
println(add2(3,2))//5
}
}

●函数可以赋值给变量并将可以当作参数进行传递

​ 定义一个函数,接收两个参数,返回两个数的和

​ 定义一个方法,接收两个参数和一个函数,并在方法体中调用函数,将两个参数传递给函数

package com.flyingAfish.baseTest

object FunctionDemo {
def main(args: Array[String]): Unit = {
//函数可以赋值给变量并将可以当作参数进行传递
//定义一个函数,接收两个参数,返回两个数的和
val add = (a:Int,b:Int) => a + b //证明了函数是对象,且函数可以赋值给变量
val result1: Int = operator(1,2,add) //证明了函数是对象,且函数可以当作参数进行传递
println(result1)//3 //函数的好处:
//可以将我们要进行的操作进行传递!!!
//也就是函数式编程的核心思想:行为参数化!!!
val result2: Int = operator(1,2, (a,b)=> a*b)
println(result2) println("=======================")
//再来体会一下:行为参数化!!!
//val list = List(1,2,3,4,5)
val list = 1 to 5
//val f = (i:Int) => println(i)
//list.foreach((i:Int) => println(i))
//list.foreach(i => println(i))
//list.foreach(println(_))
list.foreach(println)
} //定义一个方法,接收两个参数和一个函数,并在方法体中调用函数,将两个参数传递给函数
def operator(a:Int,b:Int,fun:(Int,Int)=>Int) ={
fun(a,b)
}
}

●方法可以转换成函数

​ 证明方法无返回值也可以调用

​ Java里面方法无返回值不能调用

package com.flyingAfish.baseTest

object I_FunctionDemo4 {
def main(args: Array[String]): Unit = {
println(fizz()) //() 证明函数五返回值也可以条用,打印的是空括号()
println(fizz _) //下划线 _可以将方法变成函数 //<function0>
} def fizz() = { }
}

4.总结

●定义方法:

​ def 方法名(参数名1: 参数类型1, 参数名2: 参数类型2) : 返回类型 = {方法体}

●定义方法简写法:

​ def 方法名(参数名1: 参数类型1, 参数名2: 参数类型2) = {方法体}

​ def 方法名 = {方法体}

●定义函数完整语法:

​ val函数名称 :(参数类型)=>函数返回值类型 = (参数名称:参数类型)=>函数体

●定义函数简写语法:

​ val函数名名称 = (参数名称:参数类型) => 函数体

![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml19704\wps4.png)

●注意:

​ 严格的来说,函数与方法是不同的东西。定义方式上也有很多的区别

​ 但是在Scala中,函数本身是对象,方法可以通过下划线_转换为函数。

结论:在Scala中

​ 方法可以转换为函数,函数本质上就是对象

​ 函数式编程的核心思想、灵魂所在:行为参数化!

二、Scala常用数据结构/集合

(一)Scala集合分类和继承体系

1.分类

●集合分类-按照数据结构特点分

​ Scala的集合都扩展自Iterable特质(先理解为接口)

​ 有三大类:Seq序列(List)、Set、Map映射

●集合分类-按照可变和不可变分(注意:这里的可变和不可变指的是集合的内容和长度,和之前的var/val有区别)

​ 大部分的集合Scala都同时提供了可变和不可变的版本。

​ 开发时建议Scala优先采用不可变集合(默认即为不可变),满足不了需求是再使用可变集合

●可变集合和不可变集合相应的包为:

​ 不可变集合:scala.collection.immutable (默认)

​ 可变集合: scala.collection.mutable

●注意

val和可变不可变

​ var和val指的是:变量能否被重新赋值

​ 集合可不可变指的是:集合长度或内容可不可变

对于数组:

​ 不可变数组Array:长度不可变,元素可变(定长数组)

​ 可变数组ArrayBuffer:长度和里面的元素都可变(变长数组)(注意:Java里面数组长度不可变)

对于其他集合:

​ 不可变集合immutable:长度和内容都不可变,如果调用添加或者删除方法,会产生新的集合,原集合不变

​ 可变集合mutable:长度和内容都可变

总结:

​ 开中优先使用不可变,如果满足不了需求再使用可变

2.继承体系

●不可变集合(immutable )继承层次:

![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml19704\wps5.png)

●可变集合(mutable)继承层次:

![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml19704\wps6.png)

(二)数组

●不可变/定长数组:

val/var 变量名= new Array[T](数组长度)//scala.collection.immutable包下,不需要导包,默认就是
val/var 变量名 = Array(元素1, 元素2, 元素3...)

●可变/变长数组:

val/var 变量名 = ArrayBuffer[T]() //需要手动导入import scala.collection.mutable.ArrayBuffer包
val/var 变量名 = ArrayBuffer(元素1, 元素2, 元素3...)

●数组操作

指定分隔符 mkString

将数组转换成数组缓冲 toBuffer(打印Buffer可以看到数组内容)

根据索引获取元素 ()

添加元素 +=

删除元素 -=

追加一个数组到变长数组 ++=

往指定角标插入元素 insert

删除指定角标的元素 remove

定长=>>变长 toBuffer

变长=>>定长 toArray

多维数组 Array.ofDimDouble

●遍历数组

1.可以for循环直接遍历数组

2.可以遍历下标再根据下标获取元素

3.回忆一下生成指定范围的序列

0 to n 生成[0,n]

0 until n 生成[0,n)

●数组其他常用方法

在Scala中,数组上的某些方法对数组进行相应的操作非常方便!

sum求和

max求最大值

min求最小值

sorted排序

reverse反转

●代码演示

package com.flyingAfish.baseTest
import scala.collection.mutable object ArrayDemo {
def main(args: Array[String]): Unit = {
val arr: Array[Int] = Array(5,6,7,1,2,3,4,8,9)//不可变
//不可变==>可变
val arr2: mutable.Buffer[Int] = arr.toBuffer
//可变==>不可变
val arr3: Array[Int] = arr2.toArray //遍历
for(i <- arr) println(i)
println("====================")
//arr.foreach((i:Int)=>println(i))
//arr.foreach(i=>println(i))
//arr.foreach(println(_))
arr.foreach(println)//行为参数化
println("====================")
//逆序
for(i <- arr.reverse) println(i)
println("====================")
//通过索引遍历
for(i <- 0 until arr.length) println(arr(i)) //统计
println(arr.sum)
println(arr.max)
println(arr.min)
println(arr.reverse.mkString(","))
println(arr.sorted.mkString(","))//按照默认的排序规则排序-升序
println(arr.sortBy((i:Int) => -i).mkString(",")) //降序
println(arr.sortWith((x:Int,y:Int) => x > y).mkString(","))//降序 }
}

(三)元组

​ 元组也是可以理解为一个容器,可以用来存放各种相同或不同类型的数据。例如:姓名,年龄,性别,出生年月。

元组的元素是不可变的

●创建元组

​ 使用括号来定义元组

val/var 元组 = (元素1, 元素2, 元素3....)
val animal = ("fish","cat","dog")
val world = ("fizz",34,animal,34.43)

​ 使用箭头来定义元组(元组只有两个元素)

val/var 元组 = 元素1->元素2 //对偶/二元组是最简单的元组(k,v)
val animal: (String, String) = ("fizz", "dgo")
val dog: (String, Int) = "god" -> 3

●获取元组中的值

//使用下划线加脚标 ,例如 元组名._1  元组名._2 元组名._3
val animal: (String, String) = ("fizz", "dgo")
val dog: (String, Int) = "dog" -> 3
val name: String = animal._1
val age: Int = dog._2

注意:元组中的元素脚标是从1开始的

●将对偶(二元组)组成的数组转换成映射(映射就相当于Java中的Map,后面会讲)

将对偶/二元组的集合转换成映射:

调用其toMap 方法

![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml19704\wps7.png)

●遍历

​ 可以调用元组的productIterator方法获取迭代器对象进行遍历

●代码演示

package com.flyingAfish.baseTest

object TupleDemo {
def main(args: Array[String]): Unit = {
//使用括号来定义元组
//val/var 元组 = (元素1, 元素2, 元素3....)
val t1: (String, Double, Int) = ("hadoop",3.14,110) //元组里可以存放不同类型的元素
//使用箭头来定义元组(元组只有两个元素)
//val/var 元组 = 元素1->元素2 //对偶/二元组是最简单的元组(k,v)
val t2: (String, Int) = "age"->18
val t3 = ("age",18)
println(t1)
println(t2)
println(t3)
println(t1.getClass)
println(t2.getClass)
println(t3.getClass) //获取元素
println(t1._1)
println(t1._2)
println(t1._3) println("============")
//val iterator: Iterator[Any] = t1.productIterator
for(i <- t1.productIterator) println(i) //将二元组组成的集合转成map
val ts = Array(("jack",60),("tom",70),("rose",80))
val map: Map[String, Int] = ts.toMap
println(map)//Map(jack -> 60, tom -> 70, rose -> 80)
}
}

(四)List

●高能预警

​ List操作的API方法和符号特别特别多,不用刻意去记,后续学习中会使用一些常见的,用的多了就掌握了!

●List介绍

​ 列表是scala中最重要的、也是最常用的数据结构。在scala中,也有两种列表,一种是不可变列表、另一种是可变列表

但都具备以下性质:

​ 可以保存重复的值

​ 有先后顺序

●不可变列表(默认)

​ import scala.collection.immutable._

​ 创建方式1.使用List(元素1, 元素2, 元素3, ...)来创建一个不可变列表

val/var 变量名 = List(元素1, 元素2, 元素3...)
val strings: List[String] = List("book","subject","car")
val book: List[Any] = List("English", 32, "chinese", 300)

​ 创建方式2.使用::方法创建一个不可变列表

val/var 变量名 = 元素1 :: 元素2 :: Nil
val money: List[Int] = 34 :: 34 :: 344 :: Nil

注意:

​ 使用::拼接方式来创建列表,必须在最后添加一个Nil表示空列表

●可变列表

​ import scala.collection.mutable._

​ 创建方式1.使用ListBuffer元素类型创建空的可变列表

val/var 变量名 = ListBuffer[Int]()
val fizz: ListBuffer[Int] = ListBuffer[Int]()

​ 创建方式2.使用ListBuffer(元素1, 元素2, 元素3...)创建可变列表

val/var 变量名 = ListBuffer(元素1,元素2,元素3...)
val personName: ListBuffer[Any] = ListBuffer("kashke",34,"wangzida")

●head和tail

​ 在Scala中列表要么为Nil(Nil表示空列表)

​ 要么是一个head元素加上一个tail列表。

//head为列表第一个元素,tail为列表除第一个元素外的元素列表
val list1 = List(1,2,3,4,5)
println(list1.head)//1
println(list1.tail)//List(2, 3, 4, 5)
val list = List(1)
println(list)//List(1)
println(list.head)//1
println(list.tail)//List()

●::操作符

:: 操作符是将给定的头和尾创建一个新的列表,原列表不变
:: 操作符是右结合的,如1 :: 5 :: 2 :: Nil相当于 1 :: (5 :: (2 :: Nil)) ==> List(1,5,2)

●可变列表操作

 获取/更改元素(使用括号访问(索引值))
添加元素(+=)
追加一个列表(++=)
删除元素(-=)
转换为List(toList)
转换为Array(toArray)

●扩展:list其他操作符(了解)

::  (x: A): List[A]                            在列表的头部添加一个元素或列表
+: (elem: A): List[A] 在列表的头部添加一个元素
:+ (elem: A): List[A] 在列表的尾部添加一个元素
++ [B](that: GenTraversableOnce[B]): List[B] 从列表的尾部添加另外一个列表
::: (prefix: List[A]): List[A] 在列表的头部添加另外一个列表

●扩展:等价操作(了解)

val left = List(1,2,3)
val right = List(4,5,6)
//以下操作等价
left ++ right // List(1,2,3,4,5,6)
right.:::(left) // List(1,2,3,4,5,6)
//以下操作等价
0 +: left //List(0,1,2,3)
left.+:(0) //List(0,1,2,3)
//以下操作等价
left :+ 4 //List(1,2,3,4)
left.:+(4) //List(1,2,3,4)
//以下操作等价
0 :: left //List(0,1,2,3)
left.::(0) //List(0,1,2,3)

●代码演示

package com.flyingAfish.baseTest

object ListDemo {
def main(args: Array[String]): Unit = {
//●不可变列表
//val/var 变量名 = List(元素1, 元素2, 元素3...)
val list1 = List(1,2,3,4,5)
//val/var 变量名 = 元素1 :: 元素2 :: Nil
val list2 = 1::2::Nil //List(1,2) //●可变列表
//val/var 变量名 = ListBuffer[Int]()
import scala.collection.mutable.ListBuffer
val list3 = ListBuffer[Int]()
//val/var 变量名 = ListBuffer(元素1,元素2,元素3...)
val list4 = ListBuffer(1,2,3,4)
list3.append(1,2,3) println(list1)
println(list2)
println(list3)//ListBuffer(1, 2, 3)
println(list4)
//List(1, 2, 3, 4, 5)
//List(1, 2)
//ListBuffer(1, 2, 3)
//ListBuffer(1, 2, 3, 4) println(list1.head)//1
println(list1.tail)//List(2, 3, 4, 5)
val list = List(1)
println(list)//List(1)
println(list.head)//1
println(list.tail)//List() println("============")
list3.remove(1)//根据索引删除
println(list3)//ListBuffer(1, 3)
list3 += 4
list3 -= 1 val list5 = list3.toList
val list6 = list3.toArray val list7 = 0 +: list3
println(list7)//ListBuffer(0, 3, 4) list7 //遍历
for(i <- list3) println(i)
list3.foreach(println)
}
}

(五)队列

●说明

​ 队列数据存取符合先进先出的策略

​ 有 scala.collection.mutable.Queue 和 scala.collection.immutable.Queue

​ 一般来说我们在开发中队列通常使用可变队列(特殊),其他都推荐使用不可变

●常见操作

​ enqueue入队/+=追加

​ dequeue出队

●代码演示

package com.flyingAfish.baseTest
import scala.collection.mutable object DueueDemo {
def main(args: Array[String]): Unit = {
//队列在开发中一般使用可变队列
val q = mutable.Queue[Int]()
q.enqueue(1)
q.enqueue(2)
q.enqueue(3)
q += 4
q.+=(5)
println(q)//Queue(1, 2, 3, 4 , 5)
val i: Int = q.dequeue()
println(i)//1
}
}

(六)Set

●Set说明

​ Set代表一个没有重复元素的无序集合;即无法加入重复元素且不保证插入顺序的。

●不可变Set(默认)

import scala.collection.immutable._

​ 1.创建一个空的不可变集,语法格式:

val/var 变量名 = Set[类型]()
val movie = Set[String]()

​ 2.给定元素来创建一个不可变集,语法格式:

val/var 变量名 = Set(元素1, 元素2, 元素3...)
val fresh = Set("apple","pear","apricot")

●可变Set

import scala.collection.mutable._

​ 格式相同,导包不同

Set操作

方法 描述
def +(elem: A): Set[A] 为集合添加新元素,并创建一个新的集合,除非元素已存在
def -(elem: A): Set[A] 移除集合中的元素,并创建一个新的集合
def contains(elem: A): Boolean 如果元素在集合中存在,返回 true,否则返回 false。
def &(that: Set[A]): Set[A] 返回两个集合的交集
def &~(that: Set[A]): Set[A] 返回两个集合的差集
def ++(elems: A): Set[A] 合并两个集合

●代码演示

package com.flyingAfish.baseTest

object SetDemo {
def main(args: Array[String]): Unit = {
//●不可变Set(默认)
//val/var 变量名 = Set(元素1, 元素2, 元素3...)
val set1 = Set(1,2,3,4,5,6,7) //●可变Set
//格式相同,导包不同
//val/var 变量名 = Set[类型]()
import scala.collection.mutable._
val set2 = Set[Int]()
set2.add(1)
set2.add(2)
set2.add(3)
val set3 = set2 + 4
val set4 = set2 - 1
set2.remove(2)
println(set2)//Set(1, 3)
println(set3)//Set(1, 2, 3, 4)
println(set4)//Set(2, 3) val set5 = set2 ++ set3 //并集
println(set5)//Set(1, 2, 3, 4) val set6 = set3 & set2
println(set6)//Set(1, 3)//交集 val set7 = set3 &~ set2//差集
println(set7)//Set(2, 4) //遍历和其他集合一样
}
}

(七)Map

●说明

​ 在Scala中,把哈希表这种数据结构叫做映射类比Java的map集合

●不可变Map

import scala.collection.immutable.Map

​ 格式一:使用箭头

val/var map = Map(键->值, 键->值, 键->值...)   // 推荐,可读性更好
val hero = Map("fish"->"潮汐海灵","zeus"->"宙斯","baiqi"->"白起")

​ 格式二:利用元组

val/var map = Map((键, 值), (键, 值), (键, 值), (键, 值)...)
val subject = Map(("math","数学"),("English","英语"),("physics","物理"))

●可变Map

import scala.collection.mutable.Map

​ 格式相同,导包不同

●获取值

map(键)
map.get(键)
map.getOrElse(键,默认值)//根据键取值,如果取到了则返回,没取到返回指定的默认值

●修改值

map(键)=值

●增加值

map.put(键,值)

●代码演示

package cn.fizz.collection

object MapDemo {
def main(args: Array[String]): Unit = {
//●不可变Map
//●可变Map
//格式相同,导包不同
import scala.collection.mutable._
//格式一:使用箭头val/var map = Map(键->值, 键->值, 键->值...) // 推荐,可读性更好
val map1 = Map("tom"->60,"rose"->70,"jack"->80,"zhaosi"->100)
//格式二:利用元组val/var map = Map((键, 值), (键, 值), (键, 值), (键, 值)...)
val map2 = Map(("tom",60),("rose",70),("jack",80),("zhaosi",100))
map1.put("lily",90)
map1.remove("tom")
println(map1)
println(map2) //根据key取值
//Option是None和Some的父类
//None表示空的,什么都没有
//Some表示里面有一个元素,在使用get就可以取出来
val op: Option[Int] = map1.get("zhaosi")
println(op.get)//100 //直接使用get方法不好,如果没有指定的key,继续操作可能会报错
//val op2: Option[Int] = map1.get("zaosi")
//println(op2.get) val v: Int = map1.getOrElse("zaosi",0)
println(v)//0 val v2: Int = map1.getOrElse("zhaosi",0)
println(v2)//100 println("==========================")
//遍历
//1.通过key
for(k <- map1.keySet) println(map1(k))
println("==========================")
//2.直接遍历value
for(v <- map1.values) println(v)
println("==========================")
//3.通过元组
for((k,v) <- map1) println(k+":"+v)
println("==========================")
//4.函数式的遍历+模式匹配
map1.foreach{
case (k,v) => println(k+":"+v)
}
}
} --------------------------------------------------------------------
-----------------------java版本-------------------------------------
-------------------------------------------------------------------- import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set; public class MapDemo {
public static void main(String[] args){
Map<String, Integer> map = new HashMap<>();
map.put("k1",1);
map.put("k2",2);
map.put("k3",3);
map.put("k4",4); Set<String> set = map.keySet();
for (String k : set) {
System.out.println(map.get(k));
}
Collection<Integer> values = map.values();
for (Integer value : values) {
System.out.println(value);
}
//开发的时候建议使用entrySet
//因为entrySet拿出来的就是所有的kv,不需要在根据k去找v!!!
Set<Map.Entry<String, Integer>> entries = map.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
System.out.println(entry.getKey() + ":"+entry.getValue());
}
}
}

第一章 Scala基础篇的更多相关文章

  1. 《零成本实现Web自动化测试--基于Selenium》第一章 自动化测试基础

    第一篇 Selenium 和WebDriver工具篇 第一章 自动化测试基础 1.1    初识自动化测试 自动化测试有两种常见方式 1.1.1 代码驱动测试,又叫测试驱动开发(TDD) 1.1.2 ...

  2. [Python笔记][第一章Python基础]

    2016/1/27学习内容 第一章 Python基础 Python内置函数 见Python内置函数.md del命令 显式删除操作,列表中也可以使用. 基本输入输出 input() 读入进来永远是字符 ...

  3. ASP.NET自定义控件组件开发 第一章 第三篇

    原文:ASP.NET自定义控件组件开发 第一章 第三篇 第三篇:第一章的完结篇 系列文章链接: ASP.NET自定义控件组件开发 第一章 待续 ASP.NET自定义控件组件开发 第一章 第二篇 接着待 ...

  4. 第一章 jQuery基础

    第一章jQuery基础 一.jQuert简介 1.什么是jQuery jQuery是javaScript的程序库之一,它是javaScript对象和实用函数的封装. jQuery是继Prototype ...

  5. web前端学习python之第一章_基础语法(二)

    web前端学习python之第一章_基础语法(二) 前言:最近新做了一个管理系统,前端已经基本完成, 但是后端人手不足没人给我写接口,自力更生丰衣足食, 所以决定自学python自己给自己写接口哈哈哈 ...

  6. web前端学习python之第一章_基础语法(一)

    web前端学习python之第一章_基础语法(一) 前言:最近新做了一个管理系统,前端已经基本完成, 但是后端人手不足没人给我写接口,自力更生丰衣足食, 所以决定自学python自己给自己写接口哈哈哈 ...

  7. UNIX环境高级编程--第一章 UNIX基础知识

    第一章 UNIX基础知识 1.2 UNIX体系结构   从严格意义上说,可将操作系统定义为一种软件,它控制计算机硬件资源,提供程序运行环境.我们将这种软件称为内核(kernel),因为 它相对较小,且 ...

  8. 第一章 –– Java基础语法

    第一章 –– Java基础语法 span::selection, .CodeMirror-line > span > span::selection { background: #d7d4 ...

  9. python第一章计算机基础

    第一章 计算机基础 1.1 硬件 计算机基本的硬件由:CPU / 内存 / 主板 / 硬盘 / 网卡 / 显卡 / 显示器 等组成,只有硬件但硬件之间无法进行交流和通信. 1.2 操作系统 操作系统用 ...

随机推荐

  1. Gym 100548F Color 给花染色 容斥+组合数学+逆元 铜牌题

    Problem F. ColorDescriptionRecently, Mr. Big recieved n flowers from his fans. He wants to recolor th ...

  2. 预处理、const、static、sizeof-说明内联函数使用的场合

    1:首先使用inline函数可以完全取代表达式形式的宏定义. 内联函数在C++类中的应用最广的应该是用来定义存取函数.我们定义的类中一般会把数据成员定义成私有的或者保护的,这样,外界就不能直接读写我们 ...

  3. [Tex学习笔记]章节用罗马字母编号

    微信扫描如上二维码关注跟锦数学微信公众账号. 详情请见那里.

  4. mac 安装laravel

    安装laravel之前先安装composer 使用 curl 指令下载: curl -sS https://getcomposer.org/installer | php 或是沒有安裝 curl ,也 ...

  5. Python——sklearn提供的自带的数据集

    sklearn提供的自带的数据集 sklearn 的数据集有好多个种 自带的小数据集(packaged dataset):sklearn.datasets.load_<name> 可在线下 ...

  6. YOLO: You Only Look Once论文阅读摘要

    论文链接: https://arxiv.org/pdf/1506.02640.pdf 代码下载: https://github.com/gliese581gg/YOLO_tensorflow Abst ...

  7. leetcode探索高级算法

    C++版 数组和字符串 正文 链表: 正文 树与图: 树: leetcode236. 二叉树的最近公共祖先 递归(先序) leetcode124二叉树最大路径和 递归 图: leetcode 547朋 ...

  8. Camera 采集图像的方法

    使用 Camera 采集图像, 实现步骤如下: 需要权限: android.permission.CAMERA android.permission.WRITE_EXTERNAL_STORAGE // ...

  9. 10 MySQL之数据备份与恢复

    01-数据备份 # 1.使用 MySQLdump 命令备份 MySQLdump 是MySQL提供的一个非常有用的数据库备份工具. MySQLdump 命令执行时,可以将数据库备份成一个文本文件,该文本 ...

  10. CentOS7出现Unit iptables.service could not be found

    CentOS7默认的防火墙不是iptables,而是firewalle. 出现此情况可能是iptables防火墙未安装. #停止firewalld服务 systemctl stop firewalld ...