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 {
}