进击大数据,Scala 语言火速入门

第1章:初识 Scala

1. Scala概述

  • Scala是一门多范式的编程语言,设计初衷集成面向对象编程和函数式编程的各种特性
  • Scala运行于Java平台(Java虚拟机),并兼容现有的Java程序
  • Scala combines object-oriented and functional programming in one concise, high-level language. Scala’s static types help avoid bugs in complex applications, and its JVM and JavaScript runtimes let you build high-performance systems with easy access to huge ecosystems of libraries.

2. Scala安装

  • Java8
1
2
3
4
5
6
Thpffcj:software thpffcj$ echo $JAVA_HOME
/Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home
Thpffcj:software thpffcj$ java -version
java version "1.8.0_191"
Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)
  • 下载并解压Scala
  • 配置到系统环境变量
1
2
3
4
5
6
Thpffcj:software thpffcj$ vi ~/.bash_profile

export SCALA_HOME=/Users/thpffcj/Public/software/scala-2.12.8
export PATH=$PATH:$SCALA_HOME/bin

Thpffcj:software thpffcj$ source ~/.bash_profile

3. Scala使用入门及对比Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Thpffcj:bin thpffcj$ ./scala
Welcome to Scala 2.12.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_191).
Type in expressions for evaluation. Or try :help.

scala> 1 + 3
res0: Int = 4

scala> res0 * 3
res1: Int = 12

scala> res0 * res1
res2: Int = 48

scala> println("Hello World")
Hello World

HelloWorld

1
2
3
4
5
public class HelloWorld{
public static void main(String[] args) {
System.out.println("Hello World");
}
}
  • Scala每行代码并不强求使用;结束,但是Java是必须的
1
2
3
4
5
object HelloWorld {
def main(args : Array[String]) {
println("Hello World")
}
}
  • 将上面代码保存为HelloWorld.scala
1
2
3
4
5
Thpffcj:data thpffcj$ scalac HelloWorld.scala 
Thpffcj:data thpffcj$ ls
HelloWorld$.class HelloWorld.class HelloWorld.scala hello.txt
Thpffcj:data thpffcj$ scala HelloWorld
Hello World

第2章:Scala 入门

1. val vs var

  • val:值
    • val 值名称:类型 = xxx
1
2
3
4
5
6
7
8
9
10
scala> val money = 100
money: Int = 100

scala> money =200
<console>:12: error: reassignment to val
money =200
^

scala> val age:Int = 20
age: Int = 20
  • var:变量
    • var 值名称:类型 = xxx
1
2
3
4
5
scala> var name:String = "zhangsan"
name: String = zhangsan

scala> name = "zhangsi"
name: String = zhangsi

2. 基本数据类型

  • Byte/Char
  • Short/Int/Long/Float/Double
  • Boolean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
scala> val a:Int = 10
a: Int = 10

scala> val b:Boolean = true
b: Boolean = true

scala> val c = false
c: Boolean = false

scala> val d = 1.1
d: Double = 1.1

scala> val e:Float = 1.1
<console>:11: error: type mismatch;
found : Double(1.1)
required: Float
val e:Float = 1.1
^

scala> val e:Float = 1.1f
e: Float = 1.1
  • 类型转换
1
2
3
4
5
6
7
8
scala> val f = 10
f: Int = 10

scala> val g = 10.asInstanceOf[Double]
g: Double = 10.0

scala> val h = 10.isInstanceOf[Int]
h: Boolean = true

3. lazy在Scala中的应用

耗费计算网路的时候可以使用 lazy

1
2
3
4
5
6
7
8
scala> val i = 1
i: Int = 1

scala> lazy val a = 1
a: Int = <lazy>

scala> a
res0: Int = 1
  • 我们现在想读取文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
scala> import scala.io.Source._
import scala.io.Source._

scala> lazy val info = fromFile("/Users/thpffcj/Public/data/HelloWorld.scala").mkString
info: String = <lazy>

scala> info
res3: String =
"object HelloWorld {
def main(args : Array[String]) {
println("Hello World")
}
}
"

4. Scala 常用 IDE

  • IDEA
  • Eclipse
  • NetBeans

5. 使用IDEA整合Maven构建应用程序

  1. 新建项目勾选 Create from archetype 并选择 scala-archetype-simple

scala-maven-01

  1. 起项目名一路 Next,选择自己安装的 Maven 地址,然后继续 Next

scala-maven-01

  1. 第一次创建项目需要下载依赖包可能会比较慢

  2. 去Plugin里下载Scala的Plugin,下载完成后重启

scala-maven-01

  1. 添加Scala-SDK

scala-maven-01

  1. 编写Hello World程序

scala-helloworld

第3章:Scala 函数

1. 方法的定义和使用

  • 函数/方法的定义
1
2
3
4
5
def 方法名(参数名:参数类型): 返回值 类型 = {
// 括号内的叫做方法体

// 方法体内的最后一行为返回值,不需要使用return
}

img

  • 我们去IDEA中试验一下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
object FunctionApp {
def main(args: Array[String]): Unit = {
println(add(2, 3))
println(three())
println(three) // 没有入参的函数,调用时括号是可以省略的
sayHello("Frank")
}

def add(x:Int, y:Int):Int = {
x+ y // 最后一行就是返回值,不需要return
}

def three() = 1 + 2

def sayHello(name:String): Unit = { // 不需要返回值
println("Say hello " + name)
}
}

2. 默认参数的使用

  • 在函数定义时,允许指定参数的默认值
1
2
3
def sayName(name:String = "Frank"): Unit = {
println(name)
}
  • 我们来看一下默认参数在Spark中的使用
1
2
3
4
$ ./spark-shell --help

--properties-file FILE Path to a file from which to load extra properties. If not
specified, this will look for conf/spark-defaults.conf.
  • 如果你没有设置配置文件,它将会去寻找conf下的spark-defaults.conf

3. 命名函数的使用

1
2
3
4
5
6
7
def main(args: Array[String]): Unit = {
println(speed(time = 10, distance = 100))
}

def speed(distance:Float, time:Float):Float = {
distance/time
}

4. 可变参数的使用

  • JDK5+:可变参数
1
2
3
4
5
6
7
8
9
10
11
12
def main(args: Array[String]): Unit = {
println(sum(1, 2))
println(sum(1, 2, 3))
}

def sum(numbers:Int*) = {
var result = 0
for (number <- numbers) {
result += number
}
result
}

5. 条件表达式

1
if(a>0) true else false

6. 循环表达式

  • to:左闭右闭
  • Range:左闭右开
  • until:左闭右开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
scala> 1 to 10 // 左闭右闭
res11: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> Range(1,10) // 左闭右开
res12: scala.collection.immutable.Range = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)

scala> 1.to(10) // 等同于 1 to 10
res13: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> Range(1,10,2) // 可以选择步长
res14: scala.collection.immutable.Range = Range(1, 3, 5, 7, 9)

scala> Range(1,10,0) // 步长不可以为0,死循环
java.lang.IllegalArgumentException: step cannot be 0.
at scala.collection.immutable.Range.<init>(Range.scala:86)
at scala.collection.immutable.Range$.apply(Range.scala:439)
... 32 elided

scala> Range(10,0,-1) // 可以从大到小来
res16: scala.collection.immutable.Range = Range(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

scala> 1 until 10 // 左闭右开 底层调用的Range
res17: scala.collection.immutable.Range = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)
  • for循环
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def main(args: Array[String]): Unit = {
for (i <- 1 to 10 if i % 2 == 0) {
println(i)
}

val courses = Array("Hadoop", "Spark", "Storm")
for (course <- courses) {
println(course)
}

// course 其实就是 courses 里面的每个元素
// => 就是将左边的 course 作用上一个函数,变成另外一个结果
// println 就是作用到 course 上的一个函数
courses.foreach(course => println(course))
}
  • while循环
1
2
3
4
5
6
7
def main(args: Array[String]): Unit = {
var (num, sum) = (100, 0)
while (num > 0) {
sum = sum + num
num = num - 1
}
}

第4章:Scala 面向对象

1. 面向对象概述

  • 封装:属性,方法封装到类中
    • Person
      • private int id, String name, Date birthday… getter/setter
      • eat sleep …
  • 继承:父类和子类之间的关系
    • User extends Person
  • 多态:父类引用指向子类对象(精髓所在 / 开发框架的基石)
    • Person person = new Person();
    • User user = new User();
    • Person person = new User();

2. 类的定义与使用

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
object SimpleObjectApp {
def main(args: Array[String]): Unit = {
val person = new People()
person.name = "Messi"
println(person.name + " .. " + person.age)

println("invoke eat method: " + person.eat())

person.watchFootball("Barcelona")

person.printInfo()
}
}

class People {
// 定义属性
var name:String = _ // 占位符
val age:Int = 10
private [this] val gender = "male"

// 定义方法
def eat():String = {
name + "eat..."
}

def watchFootball(teamName:String): Unit = {
println(name + " is watching match of " + teamName)
}

def printInfo(): Unit = {
println("gender: " + gender)
}
}

3. 构造器

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
object ConstructorApp {

def main(args: Array[String]): Unit = {
val person = new Person("zhangsan", 30)
println(person.name + ":" + person.age + ":" + person.school)

val person2 = new Person("lisi", 18, "M")
println(person2.name + ":" + person2.age + ":" + person2.school + ":" + person2.gender)
}
}

// 主构造器
class Person(val name:String, val age:Int) {

println("Person Constructor enter..." )

val school = "ustc"
var gender:String = _

// 附属构造器
def this(name: String, age:Int, gender:String) {
this(name, age) // 附属构造器的第一行的代码必须要调用主构造器或者其他附属构造器
this.gender = gender
}

println("Person Constructor leave..." )
}

4. 继承与重写

  • 继承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
object ConstructorApp {

def main(args: Array[String]): Unit = {

val student = new Student("zhangsan", 18, "Math")
println(student.name + ":" + student.major)
}
}

// major 属性需要使用var修饰
class (name:String, age:Int, var major:String) extends Person(name, age) {

println("Student Constructor enter..." )

println("Student Constructor leave..." )
}
  • 重写
1
2
3
4
5
6
7
8
9
10
class Student(name:String, age:Int, var major:String) extends Person(name, age) {

println("Student Constructor enter..." )

override val school = "peking"

override def toString: String = "override def toString : " + school

println("Student Constructor leave..." )
}

5. 抽象类

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
object AbstractApp {
def main(args: Array[String]): Unit = {
val student = new Student2()
println(student.name)
student.speak
}
}

/**
* 类的一个或者多个方法没有完整的实现(只有定义,没有实现)
*/
abstract class Person2 {
def speak

val name:String
val age:Int
}

class Student2 extends Person2 {
override def speak: Unit = {
println("speak")
}
override val name: String = "Frank"
override val age: Int = 18
}

6. 伴生类和伴生对象

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 伴生类和伴生对象
* 如果有一个class,还有一个与class同名的object
* 那么就称这个object是class的伴生对象,class是object的伴生类
*/
class ApplyTest {

}

object ApplyTest {

}

7. apply

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
object ApplyApp {
def main(args: Array[String]): Unit = {
for (i <- 1 to 10) {
ApplyTest.incr
}

println(ApplyTest.count) // 10 说明object本身就是一个单例对象

val b = ApplyTest() // ==> Object.apply

val c = new ApplyTest()
c()

// 类名() ==> Object.apply
// 对象() ==> Class.apply
}
}

class ApplyTest {
def apply() = {
println("Class ApplyTest apply...")
}
}

object ApplyTest {

println("Object ApplyTest enter...")

var count = 0

def incr = {
count = count + 1
}

// 最佳实践:在Object的apply方法中去new Class
def apply() = {
println("Object ApplyTest apply...")

// 在object中的apply中new class
new ApplyTest
}

println("Object ApplyTest leave...")
}

8. case class

1
2
3
4
5
6
7
8
9
// 通常用在模式匹配
object CaseClassApp {
def main(args: Array[String]): Unit = {
println(Dog("wangcai").name)
}
}

// case class 不用new
case class Dog(name:String)

9. trait

  • Scala中的Triat是一种特殊的概念
  • 首先我们可以将Trait作为接口来使用,此时的Triat就与Java中的接口非常类似
  • 在triat中可以定义抽象方法,就与抽象类中的抽象方法一样,只要不给出方法的具体实现即可
  • 类可以使用extends关键字继承trait,注意,这里不是implement,而是extends,在scala中没有implement的概念,无论继承类还是trait,统一都是extends
  • 类继承trait后,必须实现其中的抽象方法,实现时不需要使用override关键字
  • scala 不支持对类进行多继承,但是支持多重继承trait,使用with关键字即可
  • xxx extends ATrait with BTrait
1
2
3
4
class SparkConf(loadDefaults: Boolean)
extends Cloneable
with Logging
with Serializable

第5章:Scala 集合

1. 数组

定长数组

1
2
3
4
5
6
7
8
9
10
scala> val a = new Array[String](5)
a: Array[String] = Array(null, null, null, null, null)

scala> a.length
res0: Int = 5

scala> a(1) = "hello"

scala> a
res2: Array[String] = Array(null, hello, null, null, null)
  • 我们再来看一种其他创建数组的方法,其实它就是用了上面我们提到的apply
1
2
3
4
5
6
7
scala> val b = Array("hadoop", "spark", "storm")
b: Array[String] = Array(hadoop, spark, storm)

scala> b(1) = "flink"

scala> b
res4: Array[String] = Array(hadoop, flink, storm)
  • 我们看看数组的其他方法
1
2
3
4
5
6
7
8
9
10
11
scala> val c = Array(2, 3, 4, 5, 6, 7, 8, 9)
c: Array[Int] = Array(2, 3, 4, 5, 6, 7, 8, 9)

scala> c.sum
res5: Int = 44

scala> c.min
res7: Int = 2

scala> c.mkString(",")
res8: String = 2,3,4,5,6,7,8,9

变长数组

1
2
scala> val d = scala.collection.mutable.ArrayBuffer[Int]()
d: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()
  • 对可变数组进行操作
1
2
3
4
5
6
7
8
d += 1
d += 2
d += (3, 4, 5)
d ++= Array(6, 7, 8)
d.insert(0, 0)
d.remove(1)
d.trimEnd(2)
println(d)
  • 我们看到最后的结果是ArrayBuffer(0, 2, 3, 4, 5, 6)
  • 我们如何对变长数组迭代呢
1
2
3
4
5
6
7
for (i <- (0 until d.length).reverse) {
println(d(i))
}

for (ele <- d) {
println(ele)
}
  • 可变数组可以通过toArray方法变为定长数组
1
2
scala> d.toArray
res10: Array[Int] = Array()

2. List

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
scala> val l = List(1, 2, 3, 4, 5)
l: List[Int] = List(1, 2, 3, 4, 5)

scala> l.head
res1: Int = 1

scala> l.tail
res2: List[Int] = List(2, 3, 4, 5)

scala> Nil
res0: scala.collection.immutable.Nil.type = List()

scala> val l2 = 1 :: Nil
l2: List[Int] = List(1)

scala> val l3 = 2 :: l2
l3: List[Int] = List(2, 1)
  • 我们也可以创建变长list
1
2
3
4
5
6
7
8
9
10
11
scala> val l5 = scala.collection.mutable.ListBuffer[Int]()
l5: scala.collection.mutable.ListBuffer[Int] = ListBuffer()

scala> l5 += (4, 5, 6, 7)
res3: l5.type = ListBuffer(4, 5, 6, 7)

scala> l5.toList
res4: List[Int] = List(4, 5, 6, 7)

scala> l5.toArray
res5: Array[Int] = Array(4, 5, 6, 7)
  • 接下来我们看个方法,这个方法可以完成求和操作
1
2
3
4
5
6
7
def sum(nums:Int*):Int = {
if (nums.length == 0) {
0
} else {
nums.head + sum(nums.tail:_*)
}
}

3. Set

1
2
scala> val set = Set(1, 2, 2, 1, 4, 3)
set: scala.collection.immutable.Set[Int] = Set(1, 2, 4, 3)

4. Map

  • Map(映射)是一种可迭代的键值对(key/value)结构
  • 所有的值都可以通过键来获取
  • Map 中的键都是唯一的
  • Map 也叫哈希表(Hash tables)
  • Map 有两种类型,可变与不可变,区别在于可变对象可以修改它,而不可变对象不可以
  • 默认情况下 Scala 使用不可变 Map。如果你需要使用可变集合,你需要显式的引入 import scala.collection.mutable.Map 类
1
2
3
4
5
// 空哈希表,键为字符串,值为整型
var A:Map[Char,Int] = Map()

// Map 键值对演示
val colors = Map("red" -> "#FF0000", "azure" -> "#F0FFFF")
  • 定义 Map 时,需要为键值对定义类型。如果需要添加 key-value 对,可以使用 + 号
1
2
A += ('I' -> 1)
A += ('J' -> 5)

Map 基本操作

  • keys:返回 Map 所有的键(key)
  • values:返回 Map 所有的值(value)
  • isEmpty:在 Map 为空时返回true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
object Test {
def main(args: Array[String]) {
val colors = Map("red" -> "#FF0000",
"azure" -> "#F0FFFF",
"peru" -> "#CD853F")

val nums: Map[Int, Int] = Map()

println( "colors 中的键为 : " + colors.keys )
println( "colors 中的值为 : " + colors.values )
println( "检测 colors 是否为空 : " + colors.isEmpty )
println( "检测 nums 是否为空 : " + nums.isEmpty )
}
}
  • 输出结果为:
1
2
3
4
colors 中的键为 : Set(red, azure, peru)
colors 中的值为 : MapLike(#FF0000, #F0FFFF, #CD853F)
检测 colors 是否为空 : false
检测 nums 是否为空 : true
  • 你可以使用 ++ 运算符或 Map.++() 方法来连接两个 Map,Map 合并时会移除重复的 key
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
object Test {
def main(args: Array[String]) {
val colors1 = Map("red" -> "#FF0000",
"azure" -> "#F0FFFF",
"peru" -> "#CD853F")
val colors2 = Map("blue" -> "#0033FF",
"yellow" -> "#FFFF00",
"red" -> "#FF0000")

// ++ 作为运算符
var colors = colors1 ++ colors2
println( "colors1 ++ colors2 : " + colors )

// ++ 作为方法
colors = colors1.++(colors2)
println( "colors1.++(colors2)) : " + colors )

}
}
  • 以下通过 foreach 循环输出 Map 中的 keys 和 values
1
2
3
4
5
6
7
8
9
10
11
object Test {
def main(args: Array[String]) {
val sites = Map("runoob" -> "http://www.runoob.com",
"baidu" -> "http://www.baidu.com",
"taobao" -> "http://www.taobao.com")

sites.keys.foreach{ i =>
print( "Key = " + i )
println(" Value = " + sites(i) )}
}
}

5. Option & Some & None

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
object OptionApp extends App {

val m = Map(1 -> 2)
println(m.get(1))
println(m.getOrElse(2, "None"))
}

/**
* final case class Some[+A](@deprecatedName('x, "2.12.0") value: A) extends Option[A] {
* def isEmpty = false
* def get = value
* }
*
* case object None extends Option[Nothing] {
* def isEmpty = true
* def get = throw new NoSuchElementException("None.get")
* }
*/

6. Tuple

  • 与列表一样,元组也是不可变的,但与列表不同的是元组可以包含不同类型的元素
  • 元组的值是通过将单个的值包含在圆括号中构成的
1
2
scala> val t = (1, 3.14, "Fred")  
t: (Int, Double, String) = (1,3.14,Fred)
  • 访问元组的元素可以通过数字索引,我们可以使用 t._1 访问第一个元素, t._2 访问第二个元素
1
2
3
4
5
6
7
8
9
object Test {
def main(args: Array[String]) {
val t = (4,3,2,1)

val sum = t._1 + t._2 + t._3 + t._4

println( "元素之和为: " + sum )
}
}
  • 你可以使用 Tuple.productIterator() 方法来迭代输出元组的所有元素
1
2
3
4
5
6
7
object Test {
def main(args: Array[String]) {
val t = (4,3,2,1)

t.productIterator.foreach{ i =>println("Value = " + i )}
}
}

第6章:Scala 模式匹配

1. 基本数据类型模式匹配

  • Java:对一个值进行条件判断,返回针对不同的条件进行不同的处理
1
2
3
4
5
6
变量 match {
case value1 => 代码1
case value2 => 代码2
......
case _ => 代码N
}
  • 具体代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
object MatchApp extends App {
val names = Array("Akiho Yoshizawa", "YuiHatano", "Aoi Sola")
val name = names(Random.nextInt(names.length))

name match {
case "Akiho Yoshizawa" => println("吉老师")
case "YuiHatano" => println("波老师")
case _ => println("真不知道你们在说什么")
}

def judgeGrade(grade:String) = {
grade match {
case "A" => println("Excellent")
case "B" => println("Good")
case "C" => println("Just so so")
case _ => println("You need work harder")
}
}

judgeGrade("A")
judgeGrade("C")
judgeGrade("D")
}

加条件的模式匹配

1
2
3
4
5
6
7
8
9
10
11
12
def judgeGrade(name:String, grade:String) = {
grade match {
case "A" => println("Excellent")
case "B" => println("Good")
case "C" => println("Just so so")
case _ if (name == "lisi") => println(name + ", you are a good boy, but ...")
case _ => println("You need work harder")
}
}

judgeGrade("zhangsan", "D")
judgeGrade("lisi", "D")

2. Array模式匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
def greeting(array:Array[String]) = {
array match {
case Array("zhangsan") => println("Hi:zhangsan")
case Array(x, y) => println("Hi:" + x + "," + y)
case Array("zhangsan", _*) => println("Hi:zhangsan and other friend")
case _ => println("Hi:everybody")
}
}

greeting(Array("zhangsan"))
greeting(Array("lisi", "wangwu"))
greeting(Array("zhangsan", "lisi", "wangwu"))
greeting(Array("lisi"))

3. List模式匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
def greeting(list:List[String]) = {
list match {
case “zhangsan”::Nil => println(“Hi:zhangsan”)
case x::y::Nil => println(“Hi:” + x + “,” + y)
case “zhangsan”::tail => println(“Hi:zhangsan and other friend”)
case _ => println(“Hi:everybody”)
}
}

greeting(List(“zhangsan”))
greeting(List(“lisi”, “wangwu”))
greeting(List(“zhangsan”, “lisi”, “wangwu”))
greeting(List(“lisi”))

4. 类型匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
def matchType(obj:Any): Unit = {
obj match {
case x:Int => println(“Int”)
case s:String => println(“String”)
case m:Map[_,_] => m.foreach(println)
case _ => println(“other type)
}
}

matchType(1)
matchType(“1”)
matchType(1f)
matchType(Map(“name” -> “thpffcj”))

5. Scala异常处理

1
2
3
4
5
6
7
8
9
10
11
12
object ExceptionApp extends App {

try {
val i = 10 / 0
println(i)
} catch {
case e:ArithmeticException => println("除数不能为0")
case e:Exception => println(e.getMessage)
} finally {
// 释放资源,一定能执行
}
}

6. case class模式匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Person
case class CTO(name:String, floor:String) extends Person
case class Employee(name:String, floor:String) extends Person
case class Other(name:String) extends Person

def caseclassMatch(person: Person) = {
person match {
case CTO(name, floor) => println("CTO name is: " + name + ", floor is: " + floor)
case Employee(name, floor) => println("Employee name is: " + name + ", floor is: " + floor)
case _ => println("other")
}
}

caseclassMatch(CTO("Thpffcj", "22"))
caseclassMatch(Employee("zhagnsan", "2"))
caseclassMatch(Other("other"))

7. Some & None模式匹配(略)

第7章:Scala 函数高级操作

1. 字符串高级操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
object StringApp extends App {

val name = "Thpffcj"
val team = "AC Milan"
// 插值
println(s"Hello:$name, Welcome to $team")

val b =
"""
|这是一个多行字符串
|hello
|world
|Thpffcj
""".stripMargin
println(b)
}

2. 匿名函数

  • 匿名函数:函数是可以命名的,也可以不命名
  • (参数名:参数类型) => 函数体
1
2
3
4
5
6
7
8
9
10
scala> val m1 = (x:Int) => x+1

scala> m1(10)
res2: Int =

scala> def add = (x:Int, y:Int) => {x+y}
add: (Int, Int) => Int

scala> add(2, 3)
res3: Int = 5

3. curry函数

1
2
3
4
5
6
// 将原来接收两个参数的一个函数,转换成2个
def sum(a:Int, b:Int) = {a+b}
println(sum(2,3))

def sum2(a:Int)(b:Int) = a + b
println(sum2(2)(3))

4. 高阶函数

map

  • map:逐个去操作集合中的每个元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
scala> val l = List(1, 2, 3, 4, 5, 6, 7, 8)
l: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8)

scala> l.map((x: Int) => x + 1)
res0: List[Int] = List(2, 3, 4, 5, 6, 7, 8, 9)

scala> l.map((x) => x * 2)
res1: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16)

scala> l.map(x => x * 2)
res2: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16)

scala> l.map(_ * 2)
res3: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16)

filter

1
2
scala> l.map(_ * 2).filter(_ > 8)
res4: List[Int] = List(10, 12, 14, 16)

take

1
2
scala> l.take(4)
res5: List[Int] = List(1, 2, 3, 4)

reduce

scala当中的reduce可以对集合当中的元素进行归约操作。两两相加

reduce包含reduceLeft和reduceRight。reduceLeft就是从左向右归约,reduceRight就是从右向左归约。

1
2
3
4
5
6
7
8
scala> l.reduce(_ + _)
res6: Int = 36

scala> l.reduceLeft(_ - _)
res7: Int = -34

scala> l.reduceRight(_ - _)
res8: Int = -4

flatten

所有元素都压平

1
2
3
4
5
scala> var f = List(List(1,2),List(3,4),List(5,6))
f: List[List[Int]] = List(List(1, 2), List(3, 4), List(5, 6))

scala> f.flatten
res0: List[Int] = List(1, 2, 3, 4, 5, 6)

flatMap

1
2
3
4
5
scala> f.map(_.map((_ * 2)))
res10: List[List[Int]] = List(List(2, 4), List(6, 8), List(10, 12))

scala> f.flatMap(_.map(_ * 2))
res11: List[Int] = List(2, 4, 6, 8, 10, 12)

5. 偏函数(略)

第8章:Scala 隐式转换

需求:为一个已存在的类添加一个新的方法
Java:动态代理
Scala:隐式转换
双刃剑
Spark/Hive/MR… 调优

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
import java.io.File

//import ImplicitAspect._

object ImplicitApp {


// 定义隐式转换函数即可
implicit def man2superman(man:Man):Superman = new Superman(man.name)
val man = new Man("PK")
man.fly()
}


class Man(val name: String) {
def eat(): Unit = {
println(s"man[ $name ] eat ..... ")
}
}

class Superman(val name: String) {
def fly(): Unit = {
println(s"superman[ $name ] fly ..... ")
}
}

第9章:Scala 操作外部数据(略)

第10章:综合案例(略)

1. 项目概述

  • Spring Boot + Spring Data + Scala + Java 混编

2. 项目需求

  • 论统一元数据管理在大数据平台中的重要性(SparkSQL/Hive)
  • 构建大数据统一元数据管理
  • 元数据管理:MetaStore
    • 采集
    • 维护
    • 稽查
    • 分析

3. 项目需求分析

  • 本个项目实战:
    • 数据库管理
      • id:数据库编号
      • name:数据库名称
      • location:数据库存放在HDFS/S3/OSS等文件系统上的目录
    • 表管理:表是要属于某一个数据库
      • id:表编号
      • name:表名称
      • tableType:表类型
      • dbId:该表所属的数据库id
      • 默认存储路径:db对应的location/tableName

4. 功能开发

5. 使用postman进行交互测试

6. 扩展

附录一:Scala 图解

在线运行地址:图解 Scala 基本语法代码片段

img

(来源:图解 Scala 基本语法 V2018.12.17 - PlayScala中文社区 | Scala中文技术交流社区

引用