Spark先修课---Scala语言学习

变量定义 输入输出

条件、循环控制结构 异常处理

数据结构

容器 collection

collection容器,包含List、Vector、Set、Map

在scala.collection.mutable 中是可变容器,scala.collection.immutable 不可变容器

  • List列表

不同于其他语言,scala中List是不可变的,而且是抽象的,不能通过new来创建;直接通过List(xxx),默认会调用apply工厂方法创建列表。可指定类型,也可以不指定,同上文所说scala会自动推断类型

1
2
3
4
5
6
scala> val l = new List(1,2,3)
<console>:11: error: class List is abstract; cannot be instantiated
val l = new List(1,2,3)

scala> val l = List(1,2,3)
l: List[Int] = List(1, 2, 3)

像List、Set、Map无需导入scala.collection.immutable.XXX,因为scala默认导入了Predef对象,该对象为许多数据类型提供了别名定义,包含了List、不可变Set、不可变Map

  • Vector 不可变向量

List、Vector对应的可变版本是ListBuffer、ArrayBuffer

  • Range 不可变数字等差数列

创建如下,必须指定第三个步长参数。Range(1,5,1)等同于1 until 5,都不包含5;1 to 5包含5。同样是通过索引访问,如r(1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
scala> val r =new Range(1,5,2)
r: scala.collection.immutable.Range = Range 1 until 5 by 2

scala> 1 to 5
res24: scala.collection.immutable.Range.Inclusive = Range 1 to 5

scala> 1 until 5 //by 可以指定步长
res25: scala.collection.immutable.Range = Range 1 until 5

scala> r(1)
res28: Int = 3

scala> ('a' to 'e' by 2)(1)
res33: Char = c

  • Set 不重复元素集合

可变和不可变集合。默认不导入scala.collection.mutable.Set时,是不可变的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
scala> var s = Set(1,2,3)   // var定义set指向的对象可变
s: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

scala> s += 4 //s指向了新的Set对象
scala> s
res37: scala.collection.immutable.Set[Int] = Set(1, 2, 3, 4)

scala> val set = Set(1,2,3) // val定义set指向的对象不变
set: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

scala> set + 4 // 这是新生成了个set
res19: scala.collection.immutable.Set[Int] = Set(1, 2, 3, 4)

scala> set // set并未改变
res20: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

scala> set += 4 //报错,immutable.Set不可改变
<console>:15: error: value += is not a member of scala.collection.immutable.Set[Int]
Expression does not convert to assignment because receiver is not assignable.
set += 4

这里有一个是,Set和Map不能通过new来初始化,同上面List。但是可以如new HashSet[T](xxx)来创建,创建的依旧是Set、Map

1
2
3
4
5
6
7
8
9
10
11
import scala.collection.mutable.Set
val set = Set(1,2,3)
println(set)
set += 4
println(set)
set.add(5) // set += 5
println(set)
set ++= Set(4,5)
println("Set元素不重复",set)
set.remove(3) //set -= 3
println(set)

或许你会觉得val set,set不是指向的对象不可变吗?但set的内容为什么改变了?很简单,set是变量名,指针指向一个固定的Set对象,但是这个Set对象本身可以变。就算Set本身变了,但指针还是指向该Set对象的,没有毛病

结果如下:

1
2
3
4
5
Set(1, 2, 3)
Set(1, 2, 3, 4)
Set(1, 5, 2, 3, 4)
(Set元素不重复,Set(1, 5, 2, 3, 4))
Set(1, 5, 2, 4)

  • Map 键值对容器

键唯一,值不唯一。也分为可变和不可变两类,同Set

1
2
3
4
5
6
7
8
9
10
11
12
13
import scala.collection.mutable.Map
val map = Map("H"->"Hadoop","S"->("Spark","scala"))
println(map)
map += ("D"->"DUT") //添加key-value
println(map)
map.put("key","value") //添加key-value
map.remove("D") // map -= "D",移除key-value
println(map)
println("包含某个键,map.contains(\"Key\")",map.contains("key")) //包含某个键
println("获取键A对应的值,map.get(\"key\")="+map.get("key"))
println("所有键,map.keys",map.keys)
println("所有值,map.values",map.values)
println("合并map,map++Map(\"D\"->\"DUT\")",map++Map("D"->"DUT"))

结果为:

1
2
3
4
5
6
7
8
Map(S -> (Spark,scala), H -> Hadoop)
Map(S -> (Spark,scala), D -> DUT, H -> Hadoop)
Map(S -> (Spark,scala), key -> value, H -> Hadoop)
(包含某个键,map.contains("Key"),true)
获取键A对应的值,map.get("key")=Some(value)
(所有键,map.keys,Set(S, key, H))
(所有值,map.values,HashMap((Spark,scala), value, Hadoop))
(合并map,map++Map("D"->"DUT"),Map(S -> (Spark,scala), D -> DUT, key -> value, H -> Hadoop))

scala方法定义及参数使用

方法定义:

1
2
3
4
5
def func_name(参数名:类型,...): 返回值类型 = {
//方法体

// 最后一行是返回值,不写return
}

方法体中只有一行代码时,可不写括号,直接跟在等号后面即可
更多内容见下方代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
object Test_4_Function {
def main(args: Array[String]): Unit = {
// 函数定义
println(add(1,2))
print_name()
print_name //无需参数时,函数调用可以不带括号(注:参数都有默认值时仍要带括号)
print_name()
// 默认参数
print_name1("Spark")
print_name1()

// 命名参数
println(max(1,2))
println(max(y = 2,x = 1)) //这就是命名参数,通过参数名指定哪个是哪个,可以不按照顺序传入,但保证参数名没错

// 可变参数
println(1,2,3,4,5)
}

def add(x:Int,y:Int):Int ={ //等同于 def add(x:Int,y:Int):Int = x+y
x+y
}
def print_name(name: String="Hadoop"): Unit ={ //重载,但是未输入参数时,解释器仍按照无默认参数的函数执行;和定义函数的顺序无关
println("my name is"+name)
}
def print_name(): Unit ={
println("My name is Scala")
}

def print_name1(name: String="Hadoop"): Unit ={ //方法无返回值时,以Unit代替(从main函数可以看出来)
println("my name is"+name)
}

def max(x:Int,y:Int):Int ={
if (x>=y)
x
else
y
}

def add(nums:Int*)={
var i = 0
for(num<-nums){
i += num
}
i
}
}

输出结果如下:

1
2
3
4
5
6
7
8
9
3
My name is Scala
My name is Scala
My name is Scala
my name isSpark
my name isHadoop
2
2
15

匿名函数、高阶函数

1
2
3
4
5
val add=(a:Int,b:Int)=>a+b
//等同于下面的
val add = (_:Int)+(_:Int) //参数在函数字面量内仅出现一次可省略=>,用下划线占位(第一个_代表第一个参数)

val sum=(f:(Int,Int)=>Int,a:Int,b:Int)=>f(a,b)

Error汇集

  • Value += is not member of Int
1
2
3
4
5
6
7
8
9
10
11
var i: Int = 0

for (i <- 0 to 10) {
if (i == 2) {
i += 1
}
println(i)
}
><console>:15: error: value += is not a member of Int
Expression does not convert to assignment because receiver is not assignable.
i += 1

遇到这个问题时,头都大了,想不通这居然有错误。中文搜了一波没结果,然后我在shell窗口下输入val a = 0;var b = 1;a += b;,天,也是报这个错误,严重摧毁我学习的热情,我仔细再看了下,发现a申明成了不可变val变量,然后我猜测上面那个函数定义i的时候有两次定义,是不是内层循环中i也是val变量,之后我google英文搜了一下(google就是强),确实是这个问题。

You’re declaring i twice, one at the outer scope and one in the inner. Your for comprehension looks at the inner i, which is a val, not a var, thus shadowing the external declaration.

问题就是for循环中申明的变量是一个val,换个名字就好了

1205查看Demo代码时记录

  • java工具类Map、HashMap
  • SimpleDateFormat类,貌似是用来方便格式化日期字符串的
  • Date.getHours replaced by Calendar.get
  • StringBuilder、StringUtils
觉得有帮助的话,不妨加个鸡腿,O(∩_∩)O哈哈~