目錄
我使用的Scala版本:2.11.8
由於平常都是使用Java開發代碼,使用Scala只是爲了寫部分Spark代碼以及查看Spark源碼的,所以經常忘記,故寫一篇小結總結一下:
Scala中的基本數據類型
Byte,Char,Short,Int,Long,Float,Double Boolean(都是大寫)
val/var 變量名:數據類型 = 值
val 代表常量
var 代表變量
Scala裏的數據類型是可以自動推導的
數據類型轉換:
val b = 10.asinstanceof[Double]
b:Double = 10.0
數據類型判斷:
val b = 10.isInstanceof[Double]
b:Boolean = false
Scala中的方法
def max(x:Int,y:Int):Int = { //:返回值類型是Int
if(x>y){
x //函數體最後一行,表示返回值
}else{
y //函數體最後一行,表示返回值
}
}
方法在被調用的時候,如果方法沒有參數,可以省略括號
//自己定義SparkConf類
object SparkConfApp{
def main(args:Array[String]):Unit{
val sparkConf = new SparkConf
sparkConf.setAppName("SparkConfApp").setMaster("Yarn")
}
}
class SparkConf{
var master:String = _
val appname:String = _
var setting = new ConcurrentHashMap[String,String]() //支持併發的
// map (key,value)
//只能自己用的私有方法
private[this] def set(key:String,value:String):SparkConf{
setting.put(key,value)
this
}
def setMaster(master:String):SparkConf{
set("spark.master",master)
}
def setAppName(appname:String):SparkConf{
set("spark.app.name",appname)
}
def printInfo():Util{
println(setting.get("spark.app.name")+":"+setting.get(spark.master))
}
}
class SparkConf{
var setting = new ConcurrentHashmap[String,String]()
private[this] def set(key:String,value:String):SparkConf{
setting(key,value)
this
}
def setMaster(master:String):SparkConf{
set("spark.master",master)
}
def setAppName(appname:String):SparkConf{
set("spark.app.name",appname)
}
def printInfo():Util{
println(setting.get(spark.app.name)+":"+setting.get(spark.master))
}
object class 以及伴生對象
在scala中沒有靜態方法和靜態字段,所以在scala中可以用object來實現這些功能。例如:object SparkConfApp{} 之後,直接用對象名調用的方法SparkConfApp.xxx() 都是採用這種實現方式,例如Array.toString。在object裏定義的方法和屬性可以理解爲是靜態的。對象生不生成,其中的屬性和方法都是存在的。所以,Scala沒有Java的Static修飾符,Object下的成員和方法都是靜態的。
Class和Object都可以定義自己的Apply()方法
類名()調用Object下的Apply()方法,
變量名()調用Class下的Apply()方法
類名() ==> Object.apply
例如:val a = Array("a","b","c")
就是調用了這個Object.apply方法 {最後一般會new Class}
表面沒有new,底層肯定是new的
對象/引用() ==> Class.apply
Scala的構造器
主構造器,跟在class後面;附屬構造器第一行必是主構造器或是其他附屬構造器
class Person(val name:String,val age:Int) = {
val city:String = _
def this(name:String,age:Int,city:String)={ //附屬構造器
this(name,age) //附屬構造器第一行必是主構造器或是其他附屬構造器;
this.city=city
}
}
class Yzy(isGirlDefaults:Boolean):Unit = {
def this() = this(false)
}
```
```scala
// Scala JDBC 操作 MySQL
1. MySQL的驅動
在POM文件的dependency中添加MySQL驅動
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.28</version>
</dependency>
2. Connection
/*
因爲MySQL中的數據是在磁盤中的,要想獲取是需要connection的
是需要磁盤IO的重量級的過程。爲了避免頻繁IO(網絡IO+磁盤IO),
需要藉助POOL,連接池。池裏面放着一批,初始化的時候創建一批,
使用的時候直接從裏面拿,用完了放回池子裏面
//初始化的這三個屬性是因爲下面的getConnection方法裏需要
//這個url是從 hive-site.xml裏來的
val url = "jdbc:mysql://hadoop001:3306/ruoze_d6"
val user = "root"
val password="8090505"
//初始化sql 是之後Statement要用
val sql = "select DB_ID,DB_LOCATION_URI FROM DBS"
// 獲取Connection,getConnection方法的返回值是Connection
val connection = DriverManager.getConnection(url,user,password)
*/
3. Statement
//我們需要藉助於SQL去查詢MySQL,需要通過Statement將SQL語句傳進去
val stmt = connection.createStatement()
4. 拿到的結果是ResultSet 這是SQL的結果集
// Statement.executeQuery()的返回值是ResultSet
val rs = stmt.executeQuery(sql)
//顯示出來數據
while(rs.next()){
val dbId = rs.getLong(1) //1是列的index,意思是取第一列
val location=rs.getString(2)
println(dbId+"..."+location)
}
rs.close()
stmt.close()
connection.close
5. Close 釋放資源
IO編程:
1).打開資源
2).業務處理
3).釋放資源
val url = "jdbc:mysql://hadoop001:3306/ruoze_d6"
val user = "root"
val password="8090505"
val sql = "select DB_ID,DB_LOCATION_URI FROM DBS"
//需要把驅動加進來,這裏的驅動是從hive-site.xml中來的
Class.forName("com.mysql.jdbc.Driver")
//scala中是這樣寫的 classof[com.mysql.jdbc.Driver]
val connection = DriverManager.getConnection(url,user,password)
val stmt = connection.createStatement()
val rs = stmt.executeQuery(sql)
while(rs.next()){
val dbId = rs.getLong(1) //1是列的index,意思是取第一列
val location=rs.getString(2)
println(dbId+"..."+location)
}
rs.close()
stmt.close()
connection.close
繼承
1). new 子類() 會先觸發 new 父類(),會先觸發父類的構造器
2). 重寫: 默認走的是父類的方法,如果子類重寫,那麼調用的就是子類的方法
override def toString() = “student”
3). 抽象類:它的方法沒有具體的實現
不能直接new,而是通過子類new
abstract class A{
}
4). class D extends A with C{ extends之後可以加traits也可以加abstract的
override def xxx() = {} 但是with之後只能加traits
} 所以如果要繼承一個抽象類一個traits
要把抽象類放在with之後,traits放在with之後
Scala高階函數
所謂高階函數,是指更加人性化的一些函數
val l = List(1,2,3,4,5,6,7,8)
1. // l裏的每一個數都*2 對於集合裏的每一個元素都做一次相同的操作
用map:映射l.map((x:Int)=>x * 2)
//map是對每一個元素操作 x只是一個名字而已 隨便寫都可以
(x:Int)是指入參
l.map( _*2 ).filter(_>10).take(2) 將List中的元素都乘以2再篩選出來>10的,取前兩個
//_表示前面l裏的每一個元素
2. l.reduce((x:Int,y:Int)=>x+y) 元素之間兩兩相加
l.reduce(_+_) l.reduceleft(_+-)
l.reduce(_-_) l.reduceleft(_-_)
l.reduce((x,y)=>{
println(x+","+y)
x-y
})
3. l.fold(10)(_+_) 以10爲初始值,兩兩相加
fold以第一個參數爲初始值,做map操作
4. l.max
l.min
l.sum
l.count(_>3) //5 l中大於三的個數
5. val a = List(List(1,2,3),List(4,5),List(6,7))
a.flatten =>List(1,2,3,4,5,6,7) //把這些東西壓平
flatMap == flatten + Map
a.flatMap(_.map(_*2))
val words = lines.flatMap(_.split("\t")) //把lines先壓扁 ,再把裏面的單詞按照\t分隔
val wordCounts = words.map(x=>(x,1)).reduceByKey(_+_)
//words.map(x=>(x,1)) 把每個單詞賦值上一個1,reduce的入參是(hello,<1,1,1,1>)
讀取文件 IO
1) 讀取本地文件
//這裏的Source是來自 scala.io.Source
val lines = Source.fromFile("d:/")
for(line <- lines.getLines()){
println(line)
}
2) 讀取網絡文件
val lines = Source.fromURL("http://www.baidu.com")
for(line <- lines.getLine()){
print(line)
}
3) 讀取HDFS上的文件
val configuration = new Configuration()
val fileSystem = FileSystem.get(new URI("hdfs://hadoop001:9000"),configuration)
//創建路徑,返回值是boolean
val flag = fileSystem.mkdirs(new Path("/ruozedatag6"))
println(flag)
//寫文件
val out = fileSystem.create(new Path("/ruozedatag6/g6.txt"))
out.write("若澤數據".getBytes)
out.flush
out.close
//更改路徑
val src = new Path("")
val dst = new Path("")
val flag = fileSystem.rename(src,dst)
println(flag)
//刪除路徑
val del = fileSystem.delete(new Path("/ruozedatag6"),true)
println(flag)
集合
就是一個框,什麼東西都往裏面裝
1) 數組
有長度的
定長的數組:
val a = new Array[String](5) String[] a = new String[5]
val b = Array("yzy","lm") String[] b = {"yzy","lm"}
表面沒有new,但是底層調用 apply 方法
print(b(1)) lm print(b[1]) lm
變長的數組(ArrayBuffer):
val c = ArrayBuffer[Int]()
c += 1 c += (3,4,5) c ++= ArrayBuffer(6,7,8)
在0位置加入 c.insert(0,0)
將0位置的除去 c.remove(0) 從0位置除去3個c.remove(0,3)
從尾巴開始截斷兩個 trimEnd(2)
c.toArray 將變長數組變爲定長數組
裝的是一個類型的數據:String , Int ,Double
數組的一些自帶的函數
b.sum b.max b.min b.count(_>4)
b.mkString 將數組中的所有元素合併爲一個字符串
b.mkString("$$$") 將數組中的所有元素合併爲一個字符串,並以"$$$"分隔
b.mkString("<","$$$",">") 將數組中的所有元素合併爲一個字符串,並以"<"開始"$$$"">"結束分隔
object類!!!
StringBuilder 是線程不安全的 晚於StringBuffer
StringBuilder 1.5 ;
StringBuffer 1.0;
StringBuffer 是線程安全的 裏面有synchronized 是安全的
一般都是安全的是先出來的,因爲效率低。
ArrayList: 不安全的。
Vector: 帶synchronized的,是安全的。
ArrayList 底層數據結構
HashSet
HashMap
Array源碼中的 可變參數/變長參數,入參是可以數量變的
def add(nums : Int*):Int{
var res = 0
for(num <- nums){
res += num
}
res
}
println(add(1,2,3,4))
println(add(1.to(10):_*)) 把 range 轉換成可變參數
2) List
一個類型的N個元素 有序可重複的
定長List:
val l = List(1,2,3,4)
l.head 1 最開始的元素
l.tail List(2,3,4) 表示除去頭之後的集合
val l2 = 1 :: Nil ::表示拼接 List(1)
面試常考的:Nil 就是一個空的 List
變長ListBuffer:
val l = ListBuffer[Int]()
l += 1
l += (1,2,3)
l ++= List(1,2,3,4)
3) Set
無序不重複的
4) Map
key = value
val a = Map("yzy"->25,"lm"->18) //不可變的
a("yzy") 25
a("lm") 18
val b = mutable.Map("yzy"->25,"lm"->18) //可變的
val c = mutable.HashMap[String,Int]()
c("yzy") = 30
c += ("lm"->18,"dsds"->19)
c -= ("dsds")
Map的遍歷方式:
1. val b = mutable.Map("yzy"->18,"lm"->12)
for((key,value)<-b){
println(key+":"+value)
}
2. for(key <- b.keySet){
println(key + ":" +b.getOrElse(key,0)) getOrElse(key,0)很重要
}
3. for(value <- b.values){
println(value)
}
case class Dog(name:String)
使用的時候,不需要New
Dog("what").name what
5) Seq
6) Tuple
val a = (1,2,3,4,5,6)
函數賦值給變量
def main(args:Array[String]):Unit = {
val sayHelloFunc = sayHello _ //定義的:函數賦值給變量:空格加下劃線
} //調用: sayHelloFunc("ruozedata")
def sayHello(name:String) : Unit = {
println("Hello"+name)
}
匿名函數
(參數名:參數類型)=> 函數體 (x:Int) => x+1
匿名函數賦值給變量
val a = {x:Int => x+1}
a(10) Int = 11
函數的currying 柯里化
sum(a:Int,b:Int) = a + b 調用:sum(1,3)
sum(a:Int)(b:Int) = a + b sum(1)(3)
隱式轉換
當Scala編譯器進行類型匹配時,如果找不到合適的候選,
那麼隱式轉化提供了另外一種途徑來告訴編譯器如何將當前的類型轉換成預期類型。
一種特別常用的場景:類型增強與擴展
隱式:偷偷摸摸的
目的:悄悄地爲一個類的方法進行增強,
Java:Proxy(代理)
隱式轉換使用的時候,只需要定義好隱式轉換的內容,剩下的交個scala的運行機制去運行
def main(args:Array[String]):Unit{
//隱式轉換的核心:
// 把一個 man ==>Superman
implicit def man2superman(man:Man):Superman = new Superman(man.name)
//雖然這裏是new Man 但是底層是調用了上面的隱式轉換
val man = new Man("yzy")
man.fly()
}
class Man(val name:String){
def eat(){
println("Man eat")
}
}
class Superman(val name:String){
def fly(){
println("Superman fly")
}
}
def main(args Array[String]):Unit = {
implicit def file2RichFile(file:File):RichFile = new RichFile(file)
val file = new File("d:/")
val content = file.read()
println(content)
}
class RichFile(val file:File){
def read() = Source.fromFile(file.getPath).mkString
}
封裝 (隱式轉換)
object ImplicitAspect{
implicit def file2RichFile(file:File):RichFile = new RichFile(file)
}
調用封裝的時候直接 import ImplicitAspect._
模式匹配
Scala模式匹配,既可以匹配值,也可以匹配類型
變量 match {
case 值1 => 代碼
case 值2 => 代碼
case _ => 代碼 //其餘沒有匹配上的
}
onject MatchApp{
def main(args Array[String]) = {
val coaches = Array("鵝","禿","渣")
val coach = coaches(Random.nextInx(coaches.length))
println(coach)
}
coach match {
case "鵝" => println("鳥叔")
case "渣" => println("渣叔")
case _ => println("xxxx")
}
}
// Scala異常處理
val file = "xxx.mp4"
try {
val i = 1/0
} catch{
case e:ArithmeticException => throw new RuntimeException("除數不能爲0")
case e:Exception => e.printStackTrace
}finally{
println("finally")
}
偏函數:PartitalFunction
偏函數是方法體內沒有match的一組模式匹配
寫一組模式匹配 不能使用match
def say(name:String) = name match{
case "鵝" => println("鳥叔")
case "渣" => println("渣叔")
case _ => println("xxxx")
}
def say2():PartialFunction[String,String]{
case "鵝" => "鳥叔"
case "渣" => "渣叔"
case _ => "what"
}
println(say2(coach))