Scala基础篇
Posted -xiaoyu-
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala基础篇相关的知识,希望对你有一定的参考价值。
目录
一、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数组组成 |
●继承体系
●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可以不写,编译器可以自动推断出来
\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函数名名称 = (参数名称:参数类型) => 函数体
●注意:
? 严格的来说,函数与方法是不同的东西。定义方式上也有很多的区别
? 但是在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 )继承层次:
●可变集合(mutable)继承层次:
(二)数组
●不可变/定长数组:
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 方法
●遍历
? 可以调用元组的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基础篇的主要内容,如果未能解决你的问题,请参考以下文章