Scala高级语法


---------------------------------------------------------------------------------------
1、scala编程语言

2、Spark Core : Spark内核 ,最重要的一个部分。
3、Spark SQL : 类似于 hive 和 pig。数据分析引擎。sql语句提交到spark集群中运行。
4、Spark Streaming :类似于 storm,用于流式计算、实时计算。本质:一个离线计算。

------------------------------Scala编程语言---------------------------------------------

---------------Scala基础--------------------------
一、scala简介
1、scala是一个多范式的编程语言(支持多种方式的编程)
(1)使用面向对象编程:封装、继承、多态
(2)使用函数式编程:最大的特定
(*)优点:代码非常简洁
(*)缺点:可读性太差,尤其是隐式类、隐式函数、隐式参数

2、安装和配置scala
(*)基于JDK,先安装JDK
(*)scala:2.11.8(spark 2.1.0)
(*)配置环境变量:SCALA_HOME
(*)%SCALA_HOME%\bin 配置到path中

下载地址:https://www.scala-lang.org
文档地址:https://www.scala-lang.org/api/2.11.8/#scala.math.package

(*)开发环境
(1)REPL命令行
(2)IDEA : 需要安装scala插件。

二、Scala中的数据类型和变量常量

1、注意一点:scala中所有的数据,都是对象。
举例:1 java int 。在scala中,1 就是一个对象。

2、基本数据类型
Byte 8位有符号数字
Short 16位有符号数字
Int ...
Long
Float
Double

字符串类型
String
字符
Char

scala中字符串的插值操作:就是相当于字符串的拼接
scala> var s1 : String = "Hello "
s1: String = "Hello "

scala> "My name is Tom and ${s1}"
res1: String = My name is Tom and ${s1}

插值操作时,需要加入 s
scala> s"My name is Tom and ${s1}"
res2: String = "My name is Tom and Hello "

3、变量var和常量val

scala> val s2 :String = "Hello all"
s2: String = Hello all

scala> s2 = "Hello everyone"
<console>:12: error: reassignment to val
s2 = "Hello everyone"

4、Unit类型和Nothing类型

(1)Unit类型,就是java中的void,没有返回值

scala> val f = ()
f: Unit = ()

返回值 Unit类型
() 代表了一个函数,这个函数没有返回值

(2)Nothing类型,在执行过程中,产生了异常Exception

举例:
scala函数:scala中函数非常重要,是scala的头等公民
用法很多:函数式编程、高阶函数

def myFunction = 函数的实现

scala> def myFun = throw new Exception("Some Error")
myFun: Nothing

三、函数:头等公民

(一)scala内置函数,可以直接使用的函数

scala> max(1,2)
<console>:12: error: not found: value max
max(1,2)
^

scala> import scala.math
final package math

scala> import scala.math._
import scala.math._

_ 就相当于java中的 * 代表包内所有东西

scala> max(1,2)
res4: Int = 2

res4: Int = 2
定义了一个变量 res4 ,接收了 max 函数的返回值。scala中支持类型的推导。
res4 = ""

(二) 自定义函数
语法:

def 函数名称([参数名称:参数类型]*) : 返回值类型 = {
函数的实现
}

举例:
1、求和
scala> def sum(x:Int,y:Int):Int = x + y
sum: (x: Int, y: Int)Int

scala> sum(1,2)
res5: Int = 3

2、求阶乘,5!= 5 * 4* 3 *2* 1
递归
scala> def myFactor(x:Int):Int = {
| if(x<=1)
| 1
| else
| x*myFactor(x-1)
| }
myFactor: (x: Int)Int

scala> myFactor(5)
res6: Int = 120

注意:没有return语句。
函数的最后一句话,就是函数的返回值。

3、求输入的年份是否是闰年

闰年:
普通闰年:可以被4整除但是不能被100整除的年份
世纪闰年:可以被400整除的年份

scala> def isLeapYear(x:Int) = {
| if(( x%4 == 0 && x%100 != 0) || (x%400==0)) true
| else false
| }
isLeapYear: (x: Int)Boolean

scala> isLeapYear(2019)
res7: Boolean = false

scala> isLeapYear(2008)
res8: Boolean = true

1、( x%4 == 0 && x%100 != 0) || (x%400==0)
2、函数定义的时候,可以不写返回值,因为scala支持类型推导

四、循环语句
1、类似于java的用法 while dowhile for
2、foreach循环(Spark算子)

讲义在代码中

五、scala的函数参数

1、函数参数的求值策略
(1)call by value :

对函数的实参求值,并且只求一次

(2)call by name : =>

函数实参在函数体内部用到的时候,才会被求值

举例:

scala> def test1(x:Int,y:Int) = x + x
test1: (x: Int, y: Int)Int

scala> test1(3+4,8)
res9: Int = 14

scala> def test2(x : => Int,y : => Int) = x+x
test2: (x: => Int, y: => Int)Int

scala> test2(3+4,8)
res10: Int = 14

执行过程对比:
test1 ---> test1(3+4,8) ---> test1(7,8) ---> 7+7 ---> 14
test2 ---> test2(3+4,8) ---> (3+4) + (3+4) ---> 14

(3)复杂的例子

def bar(x:Int,y : => Int) : Int = 1
x 是 value y 是 name

定义一个死循环:
def loop() : Int = loop

调用bar函数的时候:
1、bar(1,loop)
2、bar(loop,1)

哪个方式会产生死循环?

scala> def bar(x:Int,y : => Int) : Int = 1
bar: (x: Int, y: => Int)Int

scala> def loop() : Int = loop
loop: ()Int

scala> bar(1,loop)
res11: Int = 1

scala> bar(loop,1)

解析:
1、虽然 y 是 name, 每次调用的时候会被求值。但是,函数体内,没有调用到y.
2、x 是 value,对函数参数求值,并且只求一次。虽然后面没有用到x,但求值时产生了死循环。

2、scala中函数参数的类型
(1)默认参数
当你没有给参数值赋值的时候,就会使用默认值。

def fun1(name:String="Tom") :String = "Hello " + name


scala> def fun1(name:String="Tom") :String = "Hello " + name
fun1: (name: String)String

scala> fun1("Andy")
res0: String = Hello Andy

scala> fun1()
res1: String = Hello Tom


(2)代名参数
当有多个默认参数的时候,通过代名参数可以确定给哪个函数参数赋值。
def fun2(str:String = "Hello " , name:String = " Tom " ,age:Int = 20) = str + name + " age is " +age


scala> def fun2(str:String = "Hello " , name:String = " Tom " ,age:Int = 20) = str + name + " age is " +age
fun2: (str: String, name: String, age: Int)String

scala> fun2()
res2: String = Hello Tom age is 20

scala> fun2("Andy")
res3: String = Andy Tom age is 20

scala> fun2(name="Andy")
res4: String = Hello Andy age is 20


(3)可变参数
类似于java中的可变参数,即 参数数量不固定。
scala> def sum(args:Int*)= {
| var result = 0
| for(s<-args) result +=s
| result
| }
sum: (args: Int*)Int

scala> sum(1,2,3,4)
res5: Int = 10

scala> sum(1,2,3,4,3,4)
res6: Int = 17

六、懒值(lazy)

铺垫:Spark的核心是 RDD(数据集合),操作数据集合的数据,使用算子来操作RDD(函数、方法)
算子:
Transformation : 延时加载,不会触发计算
Action : 会立刻触发计算。

定义:常量如果是lazy的,他的初始化会被延迟,推迟到第一次使用该常量的时候。

举例:
scala> var x : Int = 10
x: Int = 10

scala> val y : Int = x+1
y: Int = 11

y 的值是x+1 定义后会立即进行计算

scala> lazy val z : Int = x+1
z: Int = <lazy>

z的初始化会被延迟

scala> z
res0: Int = 11

当我们第一次使用z的时候,才会触发计算

读文件:
scala> val words = scala.io.Source.fromFile("H:\\tmp_files\\student.txt").mkString
words: String =
1 Tom 12
2 Mary 13
3 Lily 15

scala> lazy val words = scala.io.Source.fromFile("H:\\tmp_files\\student.txt").mkString
words: String = <lazy>

scala> words
res1: String =
1 Tom 12
2 Mary 13
3 Lily 15

scala> lazy val words = scala.io.Source.fromFile("H:\\tmp_files\\student123123121.txt").mkString
words: String = <lazy>

定义成lazy后,初始化被延迟,所以不会抛异常

scala> val words = scala.io.Source.fromFile("H:\\tmp_files\\student123123121.txt").mkString
java.io.FileNotFoundException: H:\tmp_files\student123123121.txt (系统找不到指定的文件。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at scala.io.Source$.fromFile(Source.scala:91)
at scala.io.Source$.fromFile(Source.scala:76)
at scala.io.Source$.fromFile(Source.scala:54)
... 32 elided

七、例外:Exception

类似于java
还是有一些变化

文件操作:
scala> val words = scala.io.Source.fromFile("H:\\tmp_files\\student.txt").mkString
words: String =
1 Tom 12
2 Mary 13
3 Lily 15

scala> val words = scala.io.Source.fromFile("H:\\tmp_files\\student1231312312312.txt").mkString
java.io.FileNotFoundException: H:\tmp_files\student1231312312312.txt (系统找不到指定的文件。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at scala.io.Source$.fromFile(Source.scala:91)
at scala.io.Source$.fromFile(Source.scala:76)
at scala.io.Source$.fromFile(Source.scala:54)
... 32 elided

见代码

八、数组
1、数组的类型
(1)定长数组:Array
scala> val a = new Array[Int](10) -----> (10) 就是数组的长度
a: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)

scala> val a = new Array[String](10)
a: Array[String] = Array(null, null, null, null, null, null, null, null, null, null)

初始化赋给默认值

scala> val c : Array[String] = Array("Tom","Lily")
c: Array[String] = Array(Tom, Lily)

scala> val c : Array[String] = Array("Tom","Lily",1)
<console>:11: error: type mismatch;
found : Int(1)
required: String
val c : Array[String] = Array("Tom","Lily",1)

不能往数组中添加不同类型的元素


(2)变长数组:ArrayBuffer

scala> val d = ArrayBuffer[Int]()
<console>:11: error: not found: value ArrayBuffer
val d = ArrayBuffer[Int]()
^

scala> import scala.collection.mutable._
import scala.collection.mutable._

scala> val d = ArrayBuffer[Int]()
d: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()

scala> d += 1
res2: d.type = ArrayBuffer(1)

scala> d += 2
res3: d.type = ArrayBuffer(1, 2)

scala> d += (1,2,3,4)
res4: d.type = ArrayBuffer(1, 2, 1, 2, 3, 4)

scala> d.
++ combinations groupBy mapResult reverse to
++: companion grouped max reverseIterator toArray
++= compose hasDefiniteSize maxBy reverseMap toBuffer
++=: contains hashCode min runWith toIndexedSeq
+: containsSlice head minBy sameElements toIterable
+= copyToArray headOption mkString scan toIterator
+=: copyToBuffer indexOf nonEmpty scanLeft toList
- corresponds indexOfSlice orElse scanRight toMap
-- count indexWhere padTo segmentLength toSeq
--= diff indices par seq toSet
-= distinct init partition size toStream
/: drop inits patch sizeHint toString
:+ dropRight insert permutations sizeHintBounded toTraversable
:\ dropWhile insertAll prefixLength slice toVector
<< endsWith intersect prepend sliding transform
WithFilter equals isDefinedAt prependAll sortBy transpose
addString exists isEmpty product sortWith trimEnd
aggregate filter isTraversableAgain readOnly sorted trimStart
andThen filterNot iterator reduce span union
append find last reduceLeft splitAt unzip
appendAll flatMap lastIndexOf reduceLeftOption startsWith unzip3
apply flatten lastIndexOfSlice reduceOption stringPrefix update
applyOrElse fold lastIndexWhere reduceRight sum updated
canEqual foldLeft lastOption reduceRightOption tail view
clear foldRight length reduceToSize tails withFilter
clone forall lengthCompare remove take zip
collect foreach lift repr takeRight zipAll
collectFirst genericBuilder map result takeWhile zipWithIndex

举例:去掉数组中,最后两个元素
scala> d
res5: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 1, 2, 3, 4)

scala> d.trimEnd(2)

scala> d
res7: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 1, 2)

遍历数组:

for循环、foreach:
scala> var a = Array("Tom","Lily","Andy")
a: Array[String] = Array(Tom, Lily, Andy)

scala> for(s <- a ) println(s)
Tom
Lily
Andy

scala> a.foreach(println)
Tom
Lily
Andy

数组的常见操作举例:
scala> val myarray = Array(1,2,7,8,10,3,6)
myarray: Array[Int] = Array(1, 2, 7, 8, 10, 3, 6)

scala> myarray.max
res10: Int = 10

scala> myarray.min
res11: Int = 1

scala> myarray.sortWith(_>_)
res12: Array[Int] = Array(10, 8, 7, 6, 3, 2, 1)

scala> myarray.sortWith(_<_)
res13: Array[Int] = Array(1, 2, 3, 6, 7, 8, 10)

解释:(_>_)
完整 : sortWith函数里面,参数也是一个函数 --> 高阶函数

_>_ 函数

def comp(a:Int,b:Int) = {if(a>b) true else false}

(a,b) => {if(a>b) true else false}

(a,b) => {if(a>b) true else false} ----> _>_

_>_ 是一个函数,传入两个参数,返回值是bool

2、多维数组
和java类似,通过数组的数组来实现

scala> var matrix = Array.ofDim[Int](3,4)
matrix: Array[Array[Int]] = Array(Array(0, 0, 0, 0), Array(0, 0, 0, 0), Array(0, 0, 0, 0))

Array(0, 0, 0, 0)
Array(0, 0, 0, 0)
Array(0, 0, 0, 0)

三行四列的数组

scala> matrix(1)(2)=10

scala> matrix
res15: Array[Array[Int]] = Array(Array(0, 0, 0, 0), Array(0, 0, 10, 0), Array(0, 0, 0, 0))

数组下标是从0开始的

例子:
定义一个二维数组,其中每个元素是一个一维数组,并且长度不固定

scala> var triangle = new Array[Array[Int]](10)
triangle: Array[Array[Int]] = Array(null, null, null, null, null, null, null, null, null, null)

初始化:
scala> for(i <- 0 until triangle.length){
| triangle(i) = new Array[Int](i+1)
| }

scala> triangle
res17: Array[Array[Int]] = Array(Array(0), Array(0, 0), Array(0, 0, 0),
Array(0, 0, 0, 0), Array(0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0),
Array(0, 0, 0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0, 0, 0),
Array(0, 0, 0, 0, 0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0))

二维数组,如果使用 Array[Array[Int]](10) 声明时:
1、首先指定的是外层数据的长度
2、初始化内层数组的时候,再指定内层数组的长度

九、映射 <key,value> Map

举例:
创建一个map,来保存学生的成绩

scala> val scores = Map("Tom" -> 80,"Andy"->70,"Mike"->90)
scores: scala.collection.mutable.Map[String,Int] = Map(Mike -> 90, Tom -> 80, Andy -> 70)

1、Map[String,Int] key String value Int
2、scala.collection.mutable

scala中,映射是有两种,一种是可变map,一种是不可变map
scala.collection.mutable ---> 可变
scala.collection.immutable ---> 不可变

scala> val scores2 = scala.collection.immutable.Map("Tom" -> 80,"Andy"->70,"Mike"->90)
scores2: scala.collection.immutable.Map[String,Int] = Map(Tom -> 80, Andy -> 70, Mike -> 90)

映射的初始化:
scala> val scores2 = scala.collection.mutable.Map(("Tom",80),("Andy",70))
scores2: scala.collection.mutable.Map[String,Int] = Map(Tom -> 80, Andy -> 70)

scala> scores2=1
<console>:15: error: reassignment to val
scores2=1

映射的操作:

1、获取映射中的值
scala> val chinese = scala.collection.mutable.Map(("Tom",80),("Andy",70))
chinese: scala.collection.mutable.Map[String,Int] = Map(Tom -> 80, Andy -> 70)

scala> chinese("Tom")
res18: Int = 80

scala> chinese.get("Andy")
res19: Option[Int] = Some(70)


scala> chinese("aaaa")
java.util.NoSuchElementException: key not found: aaaa
at scala.collection.MapLike$class.default(MapLike.scala:228)
at scala.collection.AbstractMap.default(Map.scala:59)
at scala.collection.mutable.HashMap.apply(HashMap.scala:65)
... 32 elided

scala> chinese.get("Andy1231312")
res21: Option[Int] = None


chinese("aaaa") get("Andy1231312")

需求:判断key是否存在,若不存在,返回默认值

scala> if(chinese.contains("aaa")){
| chinese("aaa")
| }else{
| -1
| }
res22: Int = -1

scala> chinese.getOrElse("aaaa",-1)
res23: Int = -1


2、更新映射中的值

注意:必须是可变映射

scala> chinese
res24: scala.collection.mutable.Map[String,Int] = Map(Tom -> 80, Andy -> 70)

scala> chinese("Andy")=20

scala> chinese
res26: scala.collection.mutable.Map[String,Int] = Map(Tom -> 80, Andy -> 20)


3、映射的迭代
for foreach

scala> chinese
res27: scala.collection.mutable.Map[String,Int] = Map(Tom -> 80, Andy -> 20)

scala> for(s<-chinese) println(s)
(Tom,80)
(Andy,20)

scala> chinese.foreach(println)
(Tom,80)
(Andy,20)

foreach 高阶函数

十、元组 : Tuple

scala 中的tuple : 是不同类型值的集合

scala> val t1 = Tuple("Tom","Lily",1)
<console>:14: error: not found: value Tuple
val t1 = Tuple("Tom","Lily",1)
^

scala> val t1 = Tuple3("Tom","Lily",1)
t1: (String, String, Int) = (Tom,Lily,1)

Tuple3 代表 Tuple中有三个元素

scala> val t1 = Tuple2("Lily",1)
t1: (String, Int) = (Lily,1)

scala> val t2 = (1,2,4,"Hello")
t2: (Int, Int, Int, String) = (1,2,4,Hello)


tuple操作:

访问tuple中的元素


scala> val t1 = Tuple3("Tom","Lily",1)
t1: (String, String, Int) = (Tom,Lily,1)

scala> t1.
_1 _3 copy hashCode productArity productIterator toString zipped
_2 canEqual equals invert productElement productPrefix x

scala> t1._1
res30: String = Tom

scala> t1._3
res31: Int = 1


如何遍历Tuple中的元素
注意:Tuple并没有提供一个foreach函数,我们使用productIterator


遍历分为两步:
1、使用 productIterator 生成一个迭代器
2、遍历

scala> t1.productIterator.
!= copyToBuffer forall min reduceRightOption toIterable
## corresponds foreach minBy sameElements toIterator
+ count formatted mkString scanLeft toList
++ drop getClass ne scanRight toMap
-> dropWhile grouped next seq toSeq
/: duplicate hasDefiniteSize nonEmpty size toSet
:\ ensuring hasNext notify slice toStream
== eq hashCode notifyAll sliding toString
GroupedIterator equals indexOf padTo span toTraversable
addString exists indexWhere partition sum toVector
aggregate filter isEmpty patch synchronized wait
asInstanceOf filterNot isInstanceOf product take withFilter
buffered find isTraversableAgain reduce takeWhile zip
collect flatMap length reduceLeft to zipAll
collectFirst fold map reduceLeftOption toArray zipWithIndex
contains foldLeft max reduceOption toBuffer →
copyToArray foldRight maxBy reduceRight toIndexedSeq

scala> t1.productIterator.foreach(println)
Tom
Lily
1

十一、scala中的文件操作
类似于java的io
举例:
1、读取文件
2、读取二进制文件
3、从url中获取信息
4、写入文件

5、scala中调用java的类库

见代码

---------------Scala面向对象--------------------------

scala是一个多范式的编程语言(支持多种方式的编程)
类似于 java 有区别

一、面向对象的概念
1、封装 : 把属性和操作属性的方法,写在了一起。class
2、继承
3、多态

java中面向对象的概念,也是用与scala

二、定义类:class

举例:创建一个学生类

三、内部类(嵌套类):在一个类的内部,定义了另外一个类

见代码

四、类的构造器:两种
1、主构造器 : 和类的声明在一起,并且一个类只能有一个主构造器

class Course(var courseName:String,var grade : Int)

2、辅助构造器 : 一个类可以有多个辅助构造器,通过this来实现

五、object对象:相当于java中的static

1、Object 对象中的内容都是静态的
2、如果和类名相同,则成为伴生对象
3、scala中没有static关键字

4、举例
(1)使用object来实现单例模式:一个类里面只有一个对象
在java中,把类的构造器定义成private的,并且提供一个getInstance,返回对象
在scala中,使用object实现

(2)使用App对象:应用程序对象。
好处:可以省略main方法。

六、apply方法
val t1 = Tuple3("Tom","Lily",1)
没有new关键字,但是也创建出来对象,用了apply方法

注意:apply方法必须写在伴生对象中。

七、继承
1、extends 和java一样
object HelloWorld extends App

2、抽象类:代码中


抽象字段:

package day0323

/**
* Created by root on 2019/3/23.
*
* 抽象字段 抽象属性
*
* 定义: 没有初始值的字段
*/

abstract class Person1{
//定义抽象字段
val id :Int
val name : String
}

如果不加abstract 报错
abstract class Employee1 extends Person1{

}

下面两种方式均不会报错

class Employee2() extends Person1{
val id :Int = 1
val name : String = ""
}

class Employee2(val id:Int,val name:String) extends Person1{

}

object Demo3 {

}

八、特质(trait): 抽象类,支持多重继承

本质:scala 的一个抽象类
trait

关键字:extends Human with Action

九、包和包对象:参考讲义
package
package object

---------------Scala函数式编程--------------------------

多范式:面向对象,函数式编程(程序实现起来简单)

举例:WordCount
sc 是 SparkContext , 非常重要

一行:

var result =
sc.textFile("hdfs://xxxx/xxx/data.txt")
.flatMap(_.split(" "))
.map((_,1))
.reduceByKey(_+_)
.collect

一、复习函数:关键字 def

二、匿名函数:没有名字的函数
举例:
scala> var myarray = Array(1,2,3)
myarray: Array[Int] = Array(1, 2, 3)

scala> def fun1(x:Int):Int = x*3
fun1: (x: Int)Int

scala> (x:Int) => x*3
res0: Int => Int = <function1>

问题:怎么去调用?高阶函数
scala> fun1(3)
res1: Int = 9

scala> myarray.foreach(println)
1
2
3

scala> myarray.map((x:Int) => x*3)
res3: Array[Int] = Array(3, 6, 9)
(_,1) (_+_) 都是匿名函数。

三、高阶函数(带有函数参数的函数):把一个函数作为另外一个函数的参数值

定义一个高阶函数:
对10做某种运算
scala> def someAction(f:(Double)=>(Double)) = f(10)
someAction: (f: Double => Double)Double

解释:
(Double)=>(Double) 代表了f 的类型:入参是double,返回值也是double的函数

scala> someAction(sqrt)
res5: Double = 3.1622776601683795

scala> someAction(sin)
res6: Double = -0.5440211108893698

scala> someAction(cos)
res7: Double = -0.8390715290764524

scala> someAction(println)
<console>:16: error: type mismatch;
found : () => Unit
required: Double => Double
someAction(println)
^
def someAction(f:(Double)=>(Double)) = f(10)

someAction(sqrt) = sqrt(10)

四、高阶函数的实例
scala中提供了常用的高阶函数。

(*)map : 相当于一个循环,对某个集合中的每个元素都进行操作(接收一个函数),返回一个新的集合。

scala> var numers = List(1,2,3,4,5,6,7,8,9,10)
numers: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> numers.map((i:Int)=>i*2)
res9: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)

scala> numers.map(_*2)
res10: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)

说明:
(i:Int)=>i*2 与 _*2 等价的。

(i:Int,j:Int)=>i+j _+_

scala> numers
res11: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

不改变numbers本身的值。

(*)foreach:相当于一个循环,对某个集合中的每个元素都进行操作(接收一个函数),不返回结果。
scala> numers.foreach(println)
1
2
3
4
5
6
7
8
9
10

numers.foreach(_*2)
没有返回值。


(*) filter :过滤,选择满足的数据
举例:查询能被2整除的数字

scala> numers.filter((i:Int)=>i%2==0)
res14: List[Int] = List(2, 4, 6, 8, 10)

filter函数,参数要求:要求一个返回 bool 值的函数,筛选出所有为true的数据。

(*)zip操作:合并两个集合

scala> numers.filter((i:Int)=>i%2==0)
res14: List[Int] = List(2, 4, 6, 8, 10)

scala> List(1,2,3).zip(List(4,5,6))
res15: List[(Int, Int)] = List((1,4), (2,5), (3,6))

scala> List(1,2,3).zip(List(4,5))
res16: List[(Int, Int)] = List((1,4), (2,5))

scala> List(1).zip(List(4,5))
res17: List[(Int, Int)] = List((1,4))

(*)partition : 根据断言(就是某个条件,匿名函数)的结果,来进行分区

举例:能被2整除的分成一个区,不能被2整除的分成另外一个区。

scala> numers.partition((i:Int)=>i%2==0)
res18: (List[Int], List[Int]) = (List(2, 4, 6, 8, 10),List(1, 3, 5, 7, 9))

(*)find : 查找第一个满足条件的元素

scala> numers.find(_%3==0)
res19: Option[Int] = Some(3)

_%3==0 (i:Int)=>i%3==0 一样

(*)flatten:把嵌套的结果展开
scala> List(List(2,4,6,8,10),List(1,3,5,7,9)).flatten
res21: List[Int] = List(2, 4, 6, 8, 10, 1, 3, 5, 7, 9)


(*)flatmap : 相当于一个 map + flatten

scala> var myList = List(List(2,4,6,8,10),List(1,3,5,7,9))
myList: List[List[Int]] = List(List(2, 4, 6, 8, 10), List(1, 3, 5, 7, 9))

scala> myList.flatMap(x=>x.map(_*2))
res22: List[Int] = List(4, 8, 12, 16, 20, 2, 6, 10, 14, 18)

myList.flatMap(x=>x.map(_*2))

执行过程:
1、将 List(2, 4, 6, 8, 10), List(1, 3, 5, 7, 9) 调用 map(_*2) 方法。x 代表一个List
2、flatten

五、概念:闭包、柯里化

1、闭包:就是函数的嵌套
在一个函数的里面,包含了另一个函数的定义
可以在内函数中访问外函数的变量

举例:
def mulBy(factor:Double) = (x:Double)=>x*factor
外 内

乘以三:
scala> def mulBy(factor:Double) = (x:Double)=>x*factor
mulBy: (factor: Double)Double => Double

scala> var triple = mulBy(3)
triple: Double => Double = <function1>

相当于 triple(x:Double) = x*3

scala> triple(10)
res23: Double = 30.0

scala> triple(20)
res24: Double = 60.0

scala> var half = mulBy(0.5)
half: Double => Double = <function1>

scala> half(10)
res25: Double = 5.0

引入柯里化:
scala> mulBy(3)(10)
res26: Double = 30.0

2、柯里化
概念:柯里化函数:是把具有多个参数的函数,转化为一个函数链,每个节点上都是单一函数

def add(x:Int,y:Int) = x+y

def add(x:Int)(y:Int) = x+y

转化步骤:

原始:def add(x:Int,y:Int) = x+y

闭包:def add(x:Int) = (y:Int) => x+y

简写:def add(x:Int)(y:Int) = x+y

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

scala> add(1)(2)
res27: Int = 3

---------------Scala集合-------------------------

比较简单

1、可变集合和不可变集合(Map)

immutable mutable
举例:

scala> def math = scala.collection.immutable.Map("Tom"->80,"Lily"->20)
math: scala.collection.immutable.Map[String,Int]

scala> def math = scala.collection.mutable.Map("Tom"->80,"Lily"->20,"Mike"->95)
math: scala.collection.mutable.Map[String,Int]

集合的操作:
获取集合中的值

scala> math.get("Tom")
res28: Option[Int] = Some(80)

scala> math("Tom")
res29: Int = 80

scala> math("Tom12312312")
java.util.NoSuchElementException: key not found: Tom12312312
at scala.collection.MapLike$class.default(MapLike.scala:228)
at scala.collection.AbstractMap.default(Map.scala:59)
at scala.collection.mutable.HashMap.apply(HashMap.scala:65)
... 32 elided

scala> math.get("Tom123123123")
res31: Option[Int] = None

scala> math.contains("Tom123123123")
res32: Boolean = false

scala> math.getOrElse("Tom123123123",-1)
res33: Int = -1


更新集合中的值:注意:必须是可变集合

scala> math
res34: scala.collection.mutable.Map[String,Int] = Map(Mike -> 95, Tom -> 80, Lily -> 20)

scala> math("Tom")=0

scala> math
res36: scala.collection.mutable.Map[String,Int] = Map(Mike -> 95, Tom -> 80, Lily -> 20)

造成上述现象的原因,没有import包,如果import以后,问题解决:

scala> import scala.collection.mutable._
import scala.collection.mutable._

scala> var math = Map("Tom"->80,"Lily"->20,"Mike"->95)
math: scala.collection.mutable.Map[String,Int] = Map(Mike -> 95, Tom -> 80, Lily -> 20)

scala> math("Tom")=0

scala> math
res1: scala.collection.mutable.Map[String,Int] = Map(Mike -> 95, Tom -> 0, Lily -> 20)


添加新的元素

scala> math += "Bob"->85
res38: scala.collection.mutable.Map[String,Int] = Map(Bob -> 85, Mike -> 95, Tom -> 80, Lily -> 20)

移出一个元素
scala> math -= "Bob"
res39: scala.collection.mutable.Map[String,Int] = Map(Mike -> 95, Tom -> 80, Lily -> 20)

2、列表:可变列表,不可变列表

不可变列表 List

scala> myList.head
res40: Int = 1

scala> myList.tail
res41: List[Int] = List(2, 3)

注意:tail 是除了第一个元素外,其他的元素

可变列表:LinedList 在 scala.collection.mutable 包中

scala> var myList = scala.collection.mutable.LinkedList(1,2,3,4)
warning: there was one deprecation warning; re-run with -deprecation for details
myList: scala.collection.mutable.LinkedList[Int] = LinkedList(1, 2, 3, 4)

需求:把上面列表中,每一个元素都乘以2

游标,指向列表的开始

var cur = myList

while(cur != Nil ){

//把当前元素乘以2
cur.elem = cur.elem*2

//移动指针到下一个元素
cur = cur.next
}

scala> var cur = myList
cur: scala.collection.mutable.LinkedList[Int] = LinkedList(1, 2, 3, 4)

scala> while(cur != Nil ){
| cur.elem = cur.elem*2
| cur = cur.next
| }

scala> myList
res43: scala.collection.mutable.LinkedList[Int] = LinkedList(2, 4, 6, 8)

scala> myList.map(_*2)
warning: there was one deprecation warning; re-run with -deprecation for details
res44: scala.collection.mutable.LinkedList[Int] = LinkedList(4, 8, 12, 16)

3、序列
(*)数据库中也有序列:sequence 、 auto increment
(1)作为主键,实现自动增长
(2)提高性能,序列在Oracle是在内存中的

(*)Vector Range

举例:
Vector 是一个带下标的序列,我们可以通过下标来访问Vector中的元素

Range : 是一个整数的序列
scala> Range(0,5)
res45: scala.collection.immutable.Range = Range(0, 1, 2, 3, 4)

从0开始,到5 ,但不包括5

scala> println(0 until 5)
Range(0, 1, 2, 3, 4)

scala> println(0 to 5)
Range(0, 1, 2, 3, 4, 5)

Range可以相加
scala> ('0' to '9') ++ ('A' to 'Z')
res48: scala.collection.immutable.IndexedSeq[Char] = Vector(0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U
, V, W, X, Y, Z)

把Range转换成list
scala> 1 to 5 toList
warning: there was one feature warning; re-run with -feature for details
res49: List[Int] = List(1, 2, 3, 4, 5)

4、集(Set) : 不重复元素的集合,默认是HashSet,与java类似
scala> var s1 = Set(1,2,10,8)
s1: scala.collection.immutable.Set[Int] = Set(1, 2, 10, 8)

scala> s1 + 10
res50: scala.collection.immutable.Set[Int] = Set(1, 2, 10, 8)

scala> s1 + 7
res51: scala.collection.immutable.Set[Int] = Set(10, 1, 2, 7, 8)

scala> s1
res52: scala.collection.immutable.Set[Int] = Set(1, 2, 10, 8)

创建一个可排序的Set SortedSet

scala> var s2 = scala.collection.mutable.SortedSet(1,2,3,10,8)
s2: scala.collection.mutable.SortedSet[Int] = TreeSet(1, 2, 3, 8, 10)

判断元素是否存在
scala> s2.contains(1)
res53: Boolean = true

scala> s2.contains(1231231)
res54: Boolean = false

集的运算:
union并集 intersect 交集 diff 差集
scala> var s1 = Set(1,2,3,4,5,6)
s1: scala.collection.immutable.Set[Int] = Set(5, 1, 6, 2, 3, 4)

scala> var s2 = Set(5,6,7,8,9,10)
s2: scala.collection.immutable.Set[Int] = Set(5, 10, 6, 9, 7, 8)

scala> s1 union s2
res55: scala.collection.immutable.Set[Int] = Set(5, 10, 1, 6, 9, 2, 7, 3, 8, 4)

scala> s1 intersect s2
res56: scala.collection.immutable.Set[Int] = Set(5, 6)

scala> s1 diff s2
res57: scala.collection.immutable.Set[Int] = Set(1, 2, 3, 4)

数据库里面的union操作,要求:
列数一样
列的类型一样

select A,B from ****
union
select C,D from *****

python
pyspark

5、模式匹配:相当于java中的switch case语句 但是 功能更强大


6、样本类
定义: case class

作用:
(1)支持模式匹配,instanceof
(2)定一个 Spark SQL 中的 schema : 表结构
scala> class Fruit
defined class Fruit

scala> class Banana(name:String) extends Fruit
defined class Banana

scala> class Apple(name:String) extends Fruit
defined class Apple

scala> var a = new Apple("Apple")
a: Apple = Apple@7e446d92

scala> println(a.instanceOf[Fruit])
<console>:15: error: value instanceOf is not a member of Apple
println(a.instanceOf[Fruit])
^

scala> println(a.isInstanceOf[Fruit])
true

scala> println(a.isInstanceOf[Banana])
<console>:16: warning: fruitless type test: a value of type Apple cannot also be a Banana
println(a.isInstanceOf[Banana])
^
false

---------------Scala高级特性-------------------------
一、泛型
和java类似 T

1、泛型类:定义类的时候,可以带有一个泛型的参数

2、泛型函数:定义一个函数,可以带有一个泛型的参数


scala> def mkIntArray(elem:Int*)=Array[Int](elem:_*)
mkIntArray: (elem: Int*)Array[Int]

scala> mkIntArray(1,2,3)
res5: Array[Int] = Array(1, 2, 3)

scala> mkIntArray(1,2,3,4,5)
res6: Array[Int] = Array(1, 2, 3, 4, 5)

scala> def mkIntArray(elem:String*)=Array[String](elem:_*)
mkIntArray: (elem: String*)Array[String]

scala> def mkStringArray(elem:String*)=Array[String](elem:_*)
mkStringArray: (elem: String*)Array[String]

scala> mkStringArray("a","b")
res7: Array[String] = Array(a, b)

scala> def mkArray[T:ClassTag]

ClassTag : 表示scala在运行时候的状态信息,这里表示调用时候数据类型

scala> def mkArray[T:ClassTag](elem:T*) = Array[T](elem:_*)
mkArray: [T](elem: T*)(implicit evidence$1: scala.reflect.ClassTag[T])Array[T]

scala> mkArray(1,2)
res8: Array[Int] = Array(1, 2)

scala> mkArray("Hello","aaa")
res9: Array[String] = Array(Hello, aaa)

scala> mkArray("Hello",1)
res10: Array[Any] = Array(Hello, 1)

泛型:但凡有重复的时候,考虑使用泛型

3、上界和下界

Int x
规定x的取值范围 100 <= x <=1000

泛型的取值范围:
T

类的继承关系 A ---> B ---> C ---> D 箭头指向子类

定义T的取值范围 D <: T <: B

T 的 取值范围 就是 B C D

<: 就是上下界的表示方法

概念
上界 S <: T 规定了 S的类型必须是 T的子类或本身
下界 U >: T 规定了 U的类型必须是 T的父类或本身
scala> def mkIntArray(elem:Int*)=Array[Int](elem:_*)
mkIntArray: (elem: Int*)Array[Int]

scala> mkIntArray(1,2,3)

scala> def addTwoString[T <: String](x:T,y:T) = x +" ********* " + y
addTwoString: [T <: String](x: T, y: T)String

scala> addTwoString("Hello","World")
res11: String = Hello ********* World

scala> addTwoString(1,2)
<console>:14: error: inferred type arguments [Int] do not conform to method addTwoString's type parameter bounds [T <: String]
addTwoString(1,2)
^
<console>:14: error: type mismatch;
found : Int(1)
required: T
addTwoString(1,2)
^
<console>:14: error: type mismatch;
found : Int(2)
required: T
addTwoString(1,2)
^

scala> addTwoString(1.toString,2.toString)
res13: String = 1 ********* 2


4、视图界定 View bounds

就是上界和下界的扩展

除了可以接收上界和下界规定的类型以外,还可以接收能够通过隐式转换过去的类型

用 % 来表示

scala> def addTwoString[T <% String](x:T,y:T) = x +" ********* " + y
addTwoString: [T](x: T, y: T)(implicit evidence$1: T => String)String

scala> addTwoString(1,2)
<console>:14: error: No implicit view available from Int => String.
addTwoString(1,2)
^

scala> implicit def int2String(n:Int):String = n.toString
warning: there was one feature warning; re-run with -feature for details
int2String: (n: Int)String

scala> addTwoString(1,2)
res15: String = 1 ********* 2

执行过程:
1、调用了 int2String Int => String
2、addTwoString("1","2")


5、协变和逆变(概念)

了解概念。

概念:
协变:表示在类型参数前面加上 + 。泛型变量的值,可以是本身类型或者其子类类型。
逆变:表示在类型参数前面加上 - 。泛型变量的值,可以是本身类型或者其父类类型。


二、隐式转换

1、隐式转换函数: implicit

见代码

2、隐式参数:使用implicit 修饰的函数参数

定义一个带有隐式参数的函数:
scala> def testPara(implicit name:String) = println("The value is " + name)
testPara: (implicit name: String)Unit

scala> testPara("AAAAAAAAAAAA")
The value is AAAAAAAAAAAA

scala> implicit val name : String = "*******************"
name: String = *******************

scala> testPara
The value is *******************

定义一个隐式参数,找到两个值中比较小的那个值
100 23 -->23
"Hello" "ABC" --> ABC

scala> def smaller[T](a:T,b:T)(implicit order : T => Ordered[T]) = if(a<b) a else b
smaller: [T](a: T, b: T)(implicit order: T => Ordered[T])T

scala> smaller(1,2)
res18: Int = 1

scala> smaller("Hello","ABC")
res19: String = ABC

解释:
order 就是一个隐式参数,我们使用Scala中的 Ordered 类,表示该值可以被排序,也就是可以被比较

作用:扩充了属性的功能

3、 隐式类 在类名前 加 implicit 关键字
作用:扩充类的功能

AKKA 项目 --> scala 主从通信


------------------------Actor并发模型----------------------------------

复习:java中的并发开发

java的并发编程是基于 共享数据 和 加锁 的一种机制。锁的是共享数据。

synchronized

Scala中的并发开发:不共享数据。依赖于 消息传递 的一种并发编程模式。

如果 Actor A 和 Actor B要相互沟通:

1、A要给B传递一个消息,B有一个收件箱,B轮询自己的收件箱。
2、如果B看到A的消息,解析A的消息并执行相应操作
3、有可能会回复 A 消息。

AKKA 负责来回传递消息

----------------------------------------------

scala项目:
实现一个主从管理系统

Worker类
Master类

ActorMessage类
WorkerInfo类

ActorMessage 类:定义消息 5种消息

 

posted @ 2019-05-01 13:58  jareny  阅读(361)  评论(0编辑  收藏  举报