1. 程式人生 > >Spark學習(一)——Scala基礎學習

Spark學習(一)——Scala基礎學習

scala是一門多正規化程式語言,集成了面向物件程式設計和函數語言程式設計等多種特性。

scala執行在虛擬機器上,併兼容現有的Java程式。

Scala原始碼被編譯成java位元組碼,所以執行在JVM上,並可以呼叫現有的Java類庫。

1、第一個Scala程式:

Scala和Java最大的區別是:Scala語句末尾的分號(;)是可選的!

編譯執行:

先編譯:scalac HelloScala.scala   將會生成兩個檔案:HelloScala$.class和HelloScala.class

在執行:scala HelloScala

輸出結果:hello scala!!!

object HelloScala{

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

    println("hello scala!!!")

  }

}

2、Scala基本語法:

1) 區分大小寫;

2) 類名首字母大寫(MyFirstScalaClass);

3) 方法名稱第一個字母小寫(myMethodName());

4) 程式檔名應該與物件名稱完全匹配;

5) defmain(args:Array[String]): scala程式從main方法開始處理,程式的入口。

6) Scala註釋:分為多行/**/和單行//

7) 換行符:Scala是面向行的語言,語句可以用分號(;)結束或換行符(println())

8) 定義包有兩種方法:

其一:package com.ahu

      classHelloScala

其二:package com.ahu{

      class HelloScala

  }

引用:import java.awt.Color

如果想要引入包中的幾個成員,可以用selector(選取器):

importjava.awt.{Color,Font}

// 重新命名成員

importjava.util.{HashMap => JavaHashMap}

// 隱藏成員 預設情況下,Scala 總會引入 java.lang._ 、 scala._ 和 Predef._,所以在使用時都是省去scala.的

importjava.util.{HashMap => _, _} //引入了util包所有成員,但HashMap被隱藏了

3、Scala資料型別:

Scala與Java有著相同的資料型別,下面列出一些Scala有的資料型別。

Unit:表示無值,和其他語言的void一樣,一般函式返回時如果沒有返回值,可以新增返回值為Unit。

Null:null或空引用。

Nothing:是Scala的類層級的最低端,是任何其他型別的子型別。

Any:是所有其他類的父類。

AnyRef:是Scala所有引用類的父類。

多行字串的表示方法:

val foo="""第一行

                 第二行

                 第三行"""

4、Scala變數:

在Scala中,使用關鍵字“var”宣告變數,使用關鍵字“val”宣告常量。

var myVar1 : String= "foo"

val myVal ="Hello,Scala!"

Scala多個變數宣告:

val xmax, ymax =100  // xmax,ymax都宣告為100

Scala訪問修飾符:

Scala訪問修飾符和Java基本一樣,分別有private、protected、public。

預設情況下,Scala物件的訪問級別是public。

私有成員:用private關鍵字修飾的成員僅在包含了成員定義的類或物件內部可見。

class Outer{

  class Inner{

    private def f(){println("f")}

    class InnerMost{

      f() // 正確

    }

  }

  (new Inner).f() // 錯誤

}

保護成員:Scala比Java中更嚴格。只允許保護成員在定義了該成員的類的子類中被訪問,而在java中除了子類可以訪問,同一個包裡的其他類也可以進行訪問。

package p{

  class Super{

       protecteddef f() {println("f")}

  }

  class Sub extends Super{

     f()

  }

  class Other{

     (new Super).f()  // 錯誤

  }

}

公共成員:預設public,這樣的成員在任何地方都可以被訪問。

class Outer{

  class Inner{

    def f(){println("f")}

    class InnerMost{

      f() // 正確

    }

  }

  (new Inner).f() // 正確

}

5、作用域保護:Scala中,訪問修飾符可以通過使用限定詞強調。

private[x] 或者 protected[x]

private[x]:這個成員除了對[...]中的類或[...]中的包中的類及他們的伴生物件可見外,對其他的類都是private。

Scala運算子:和Java一樣,這裡就不再浪費時間一一介紹了。

算術運算子、關係運算符、邏輯運算子、位運算子、賦值運算子。

Scala if...else語句:和Java一樣,簡單列舉一下四種情況。

if(...){

}

if(...){

}else{

}

if(...){

}else if(...){

}else{

}

if(...){

  if(...){

  }

}

Scala迴圈:和Java一樣,這裡不贅述,只介紹三種迴圈型別。

while迴圈、do...while迴圈、for迴圈

6、Scala函式:scala中函式的地位是非常高的,因此,其變換相對比較多。

option[T]有兩個子類別:some與none;

option[String] =Some(Paris):返回string型別或者none;

當程式回傳some的時候,代表這個函式式成功的返回了一個String值,可以通過get()獲取到;如果程式返回none,則代表沒有字串給你,此時如果通過get()獲取option中的值,就會報錯;

object Test{

  def main(args: Array[String]){

    println(addInt(1,3)); // 函式呼叫

  }

函式的定義流程:

def addInt(a:Int,b:Int):Int = {

   var c:Int = 0

   c = a+b

   return c

}

傳名呼叫:

def time()={

   println("獲取時間,單位為納秒")

   System.nanoTime

}

def delayed( t :=> Long )={

   println("在delay方法內")

   println("引數:"+t)

   t

}

命名引數:

def printInt(a:Int,b:Int)={

   println("value of a :"+a)

   println("value of b :"+b)

}

可變引數:不需要指定引數的個數

defprintStrings(args:String*)={

   var i:Int = 0;

   for (arg<-args){

      println("argvalue["+i+"]="+arg);

      i = i +1

     }

}

遞迴函式:

deffactorial(n:BigInt):BigInt={

   if(n<=1)

     1

   else

     n*factorial(n-1)

}

預設引數值:

def addInt(a:Int =5, b:Int = 7):Int={

   var sum:Int = 0

   sum = a + b

   return sum

}

高階函式:操作其他函式的函式

defapply(f:Int=>String, v:Int)={

   f(v)

}

函式巢狀:

def factorial(i:Int):Int= {

   def fact(i:Int, accumulator:Int):Int={

      if(i<=1){

          accumulator

      }else{

          fact(i-1, i*accumulator)

      }

   }

   fact(i, 1)

}

匿名函式:箭頭左邊是引數列表,右邊是函式體;

var inc = (x:Int)=> x+1

函式柯里化:

原函式為:

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

defadd(x:Int)(y:Int)=x+y

類似於:

defadd(x:Int)=(y:Int)=>x+y

即轉化為呼叫兩次的一維函式

val result =add(1)(2)

}

7、Scala閉包:

閉包是一個函式,返回值依賴於宣告在函式外部的一個或多個變數。

例子:

object Test{

def main(args:Array[String]){

   println("muliplier(1) value = " +muliplier(1))

   println("muliplier(2) value = " +muliplier(2))

}

var factor = 3  // 定義在函式外的自由變數

val muliplier =(i:Int) => i * factor  // muliplier函式變數就是一個閉包

}

輸出結果:

muliplier(1) value= 3

muliplier(2) value= 6

8、Scala字串:

Scala中可以建立兩中字串:一種是不可修改的,一種是可以修改的。

// 建立不可修改的字串

var greeting:String= "Hello World!";

// 建立可以修改的字串

object Test{

  def main(args: Array[String]){

    val buf = new StringBuilder;

    buf += 'a' // 新增一個字元

    buf ++= "bcdef" // 新增一個字串

    println(buf.toString);  // 輸出:abcdef

  }

}

字串長度:xxx.length()

字串連線:可以用concat()方法或者用加號

object Test {

  def main(args: Array[String]) {

    var str1 = "字串1:";

    var str2 = "字串2";

    var str3 = "字串3:";

    var str4 = "字串4";

    println( str1 + str2 ); //  字串1:字串2

    println( str3.concat(str4) ); // 字串3:字串4

  }

}

建立格式化字串:

String類中可以使用printf()方法來格式化字串並輸出。

object Test{

  def main(args:Array[String]){

    var floatVar = 12.456

    var intVar = 2000

    var stringVar = "字串變數"

    var fs = printf("浮點型變數為 " +"%f,整形變數為 %d, 字串為 " +"%s", floatVar, intVar, stringVar)

    println(fs) // 浮點型變數為 12.456000, 整型變數為 2000, 字串為 字串變數

  }

}

特殊符號:

->:  map中的應用,類似於:                    

<-:  用於遍歷集合物件;                        

=>:  1)by name運算:將函式傳入by name引數;  

       2)函式型別:定義函式                    

       3)模式識別:case "1" =>"one"           

       4)匿名函式的應用                        

<=: 小於等於號                                

::  向佇列頭部追加資料,x::list              

:+  在尾部追加資料;                         

+:  在頭部追加資料;                         

++  連線兩個集合;set1++set2                  

:::  用於連線兩個list型別的集合;list1:::list2

正則表示式:

val pattern ="Scala".r                                                      

val str ="Scala is Scalable and scala is good"                          

try{                                                                     

   println(pattern findFirstIn str)                                      

   println((pattern findAllInstr).mkString(","))                        

   println(pattern replaceFirstIn(str,"Java"))                          

   println(pattern replaceAllIn(str,"Java"))                            

  }catch{                                                                

      case ex:FileNotFoundException =>{println("Missing file Exception")}

      case ex:IOException =>{println("IO Exception")}                   

  }finally{                                                              

      println("Exitingfinally~")                                        

  }

常見正則表示式符號:

\:       轉義字元;

^:      匹配輸入字串開始的位置;

$:       匹配輸入字串結束的位置;

*:       零次或多次匹配前面的字元或子表示式;

+:      一次或多次匹配前面的字元或子表示式;

?:       零次或一次匹配前面的字元或子表示式;

{n}:     正好匹配n次;

{n.}:    至少匹配n次;

{n,m}: 匹配n到m次;

貪心模式:(.*?)

非貪心模式:(.*)

9、Scala陣列:

1)宣告陣列

  var z:Array[String] = newArray[String](3)  或者  varz = new Array[String]()

  z(0) = "value1"; z(1) ="value2"; z(2) = "value3"

  var z = Array("value1","value2", "value3")

2)處理陣列

  object Test{

    def main(args: Array[String]){

      var myList = Array(1.1, 2.2, 3.3, 4.4)

      // 輸出所有陣列元素

      for(x <- myList){

        println(x)

      }

      // 計算陣列所有元素的總和

      var total = 0.0

      for(i <- 0 to (myList.length - 1)){

        total += myList(i)

      }

      println("總和:" + total)

      // 查詢陣列中的最大元素

      var max = myList(0)

      for(i <- 1 to (myList.length - 1)){

        if(myList(i) > max)

          max = myList(i)

      }

      println("最大值:" + max)

    }

  }

3)多維陣列

import Array._

object Test{

  def main(args: Array[String]){

    // 定義陣列

    var myMatrix = ofDim[Int](3,3)

    // 建立矩陣

    for(i <- 0 to 2){

      for(j <- 0 to 2){

        myMatrix(i)(j) = j;

      }

    }

    // 列印矩陣

    for(i <- 0 to 2){

      for(j <- 0 to 2){

        print(" " + myMatrix(i)(j));

      }

      println();

    }

  }

}

4)合併陣列

import Array._

object Test{

  defmain(args: Array[String]){

    var myList1 = Array(1.1, 2.2, 3.3, 4.4)

    var myList2 = Array(5.5, 6.6, 7.7, 8.8)

    // 使用concat()合併

    var myList3 = concat(myList1, myList2)

    // 輸出所有陣列元素

    for(x <- myList3){

      println(x)

    }

  }

}

5)建立區間陣列:使用range(x,y,z)建立區間陣列,數值範圍大於等於x,小於y。z表示步長,預設為1。

object Test{

  def main(args: Array[String]){

    var myList1 = range(10, 20, 2)

    var myList2 = range(10, 20)

    for(x <- myList1){

      print(" " + x)  //輸出:10 12 14 16 18

    }

    println()

    for(x <- myList2){

      print(" " + x)  // 輸出:10 11 12 13 14 15 16 17 18 19

    }

  }

}

10、Scala集合:分為可變集合和不可變集合。

可變集合:可以在適當的地方被更新或擴充套件,也就是可以修改、新增、移除一個集合的元素。

不可變集合:永遠不會改變。但可以模擬新增、移除、更新操作,但是這些操作將在每一種情況下都返回一個新的集合,同時使原來的集合不發生改變。

// 定義整形List

val x =List(1,2,3,4)

// 定義Set

var x =Set(1,3,5,7)

// 定義Map

val x =Map("one" -> 1, "two" -> 2, "three" ->3)

// 建立兩個不同型別的元組

val x = (10,"Runoob")

// 定義Option:如果有值返回int型,如果沒有值返回none;

val x:Option[Int] =Some(5)

11、Scala迭代器:

迭代器不是一個集合,而是一個用於訪問集合的方法。

object Test{

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

  val it = Iterator("one","two", "three", "four")

  while(it.hasNext){  // 檢測集合中是否還有元素

    println(it.next())  // 返回迭代器的下一個元素,並更新迭代器的狀態

  }

  val ita = Iterator(1, 2, 3, 4, 5)

  val itb = Iterator(11, 22, 33, 44, 55)

  //println(ita.max)  // 查詢最大元素

  //println(itb.min)  // 查詢最小元素

  println(ita.size) // 獲取迭代器的長度

  println(itb.length) // 獲取迭代器的長度

}

12、Scala類和物件:

類是物件的抽象,物件是類的具體例項。

類是抽象的,不佔用記憶體;物件是類的具體例項,佔用儲存空間。

scala中object與class的區別:

class是指一般的類;

object是指靜態類,類似於java中的static;

import java.io._

class Point(xc:Int, yc: Int){

  var x: Int = xc

  var y: Int = yc

  def move(dx: Int, dy: Int): Unit ={

    x = x + dx

    y = y + dy

    println("x點的座標是:" + x)

    println("y點的座標是:" + y)

  }

}

object Test{

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

    val pt = new Point(10, 20)

    // 移到一個新的位置

    pt.move(10, 10)

  }

}

13、Scala繼承:跟Java差不多。

1)重寫類引數、非抽象方法需要用到override修飾符

2)只有主建構函式才可以往基類的建構函式中寫引數;

3)在子類中重寫超類的抽象方法時,不需要使用override關鍵字;

class Point(val xc:Int, val yc: Int){

  var x: Int = xc

  var y: Int = yc

  def move(dx: Int, dy: Int): Unit ={

    x = x + dx

    y = y + dy

    println("x點的座標是:" + x)

    println("y點的座標是:" + y)

  }

  //-------------------------------------

  var name = ""

  override def toString = getClass.getName +"[name=" + name + "]"

}

classLocation(override val xc: Int, override val yc: Int, val zc: Int)

         extends Point(xc, yc){  // 繼承:重寫了父類的欄位

  var z: Int = zc

  def move(dx: Int, dy: Int, dz: Int){

    x = x + dx

    y = y + dy

    z = z + dz

    println("x點的座標是:" + x)

    println("y點的座標是:" + y)

    println("z點的座標是:" + z)

  }

  //---------------------------------------

  var salary = 0.0

  override def toString = super.toString +"[salary=" + salary + "]"

}

object Test{

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

    val loc = new Location(10, 20, 30)

    loc.move(10, 10 ,5)

    //------------------------------------

    loc.name = "lc"

    loc.salary = 35000.0

    println(loc)

  }

}

14、Scala單例物件:

Scala中沒有static,要使用object關鍵字實現單例模式。

Scala中使用單例模式時,除了定義類,還要定義一個同名的object物件,它和類的區別是,object物件不能帶引數。

當單例物件與某個類共享一個名稱時,他被稱作這個類的伴生物件。

必須在同一個原始檔裡定義類和它的伴生物件。

類和它的伴生物件可以互相訪問其私有成員。

私有構造方法:

class Markerprivate(val color:String) {

  println("建立" + this)

  override def toString(): String = "顏色標記:"+ color  //4:顏色標記:red

}

伴生物件:與類共享名字,可以訪問類的私有屬性和方法。

object Marker{

  private val markers: Map[String, Marker] =Map(

    "red" -> newMarker("red"), //1:建立顏色標記:red

    "blue" -> newMarker("blue"), //2:建立顏色標記:blue

    "green" -> newMarker("green")  //3:建立顏色標記:green

  )

  def apply(color:String) = {

    if(markers.contains(color)) markers(color)else null

  }

  def getMarker(color:String) = {

    if(markers.contains(color)) markers(color)else null  //5:顏色標記:blue

  }

  def main(args: Array[String]) {

    println(Marker("red"))

    // 單例函式呼叫,省略了.(點)符號

    println(Marker getMarker "blue")

  }

}

15、Scala Trait(特徵):

相當於Java的介面,但比介面功能強大,它還可以定義屬性和方法的實現。

一般情況下Scala的類只能單繼承,但特徵可以實現多重繼承。

定義特徵:

trait Equal{

  def isEqual(x: Any): Boolean  // 未實現的方法

  def isNotEqual(x: Any): Boolean = !isEqual(x)// 實現了的方法

}

class Point(xc: Int,yc: Int) extends Equal{

  var x: Int = xc

  var y: Int = yc

  override def isEqual(obj: Any): Boolean =

  obj.isInstanceOf[Point] &&

  obj.asInstanceOf[Point].x == x

}

object Test{

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

    val p1 = new Point(2, 3)

    val p2 = new Point(2, 4)

    val p3 = new Point(3, 3)

    println(p1.isNotEqual(p2))

    println(p1.isNotEqual(p3))

    println(p1.isNotEqual(2))

  }

}

16、特徵構造順序:

構造器的執行順序:

1)呼叫超類的構造器

2)特徵構造器在超類構造器之後、類構造器之前執行

3)特徵由左到右被構造

4)每個特徵當中,父特徵先被構造

5)如果多個特徵共有一個父特徵,父特徵不會被重複構造

6)所有特徵被構造完畢,子類被構造

Scala模式匹配:選擇器 match {備選項}

object Test{

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

       println(matchTest("two"))

       println(matchTest("test"))

       println(matchTest(1))

       println(matchTest(6))

  }

  def matchTest(x: Any): Any = x match {

       case1 => "one"

       case"two" => 2

       casey: Int => "scala.Int"  // 對應型別匹配

       case_ => "many"  // 預設全匹配選項

  }

}

使用樣例類:

使用case關鍵字的類定義就是樣例類,樣例類是種特殊的類,經過優化以用於模式匹配。

object Test{

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

    val alice = new Person("Alice",25)

    val bob = new Person("Bob", 32)

    val charlie = newPerson("Charlie", 27)

    for(person <- List(alice, bob,charlie)){

      person match{

        case Person("Alice", 25)=> println("Hi Alice!")

        case Person("Bob", 32) =>println("Hi Bob!")

        case Person(name, age) =>println("Age: " + age + " year,name: " + name+"?")

      }

    }

  }

  // 樣例類

  case class Person(name: String, age: Int)

}

17、Scala異常處理:

和Java類似。在Scala中借用了模式匹配的方法來在catch語句塊中來進行異常匹配。

importjava.io.{FileNotFoundException, FileReader, IOException}

object Test{

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

    try {

      val f = newFileReader("input.txt")

    }catch {

      case ex: FileNotFoundException => {

        println("Missing fileexception")

      }

      case ex: IOException => {

        println("IO Exception")

      }

    }finally {

      println("Exiting finally...")

    }

  }

}

18、Scala提取器(Extractor):

apply方法:無需new操作就可建立物件。

unapply方法:是apply方法的反向操作,接受一個物件,然後從物件中提取值,提取的值通常是用來構造物件的值。

object Test {

         def main(args: Array[String]) {

                  println("Apply 方法 : " + apply("Zara","gmail.com"));

                  //也可直接Test("Zara","gmail.com")來建立[email protected]

                  println("Unapply 方法 : " +unapply("[email protected]"));

                  println("Unapply 方法 : " + unapply("Zara Ali"));

         }

         // 注入方法 (可選)

         def apply(user: String, domain: String)= {user +"@"+ domain}

         // 提取方法(必選)

         def unapply(str: String):Option[(String, String)] = {

                val parts = str split "@"

                if (parts.length == 2){

             Some(parts(0), parts(1))

                }else{

             None

                }

         }

}

19、提取器使用模式匹配:

在我們例項化一個類的時,可以帶上0個或者多個的引數,編譯器在例項化的時會呼叫 apply 方法。

object Test {

         def main(args: Array[String]) {

       valx = Test(5)

                println(x)

       xmatch

       {

    caseTest(num) => println(x + " 是 " + num + " 的兩倍!")  //2:10是5的兩倍!

    //unapply被呼叫

    case_ => println("無法計算")

       }

         }

         def apply(x: Int) = x*2 //1:10

         def unapply(z: Int): Option[Int] = if(z%2==0) Some(z/2) else None

}

20、Scala檔案I/O:

檔案寫操作

import java.io._

object Test {

  def main(args: Array[String]) {

     val writer = new PrintWriter(newFile("test.txt" ))

     writer.write("Scala語言")

     writer.close()

   }

 }

// 從螢幕上讀取使用者輸入

object Test {

   def main(args: Array[String]) {

     print("請輸入菜鳥教程官網 : " )

     val line = Console.readLine // 在控制檯手動輸入

     println("謝謝,你輸入的是: " + line)

   }

 }

// 從檔案上讀取內容

importscala.io.Source

object Test {

   def main(args: Array[String]) {

     println("檔案內容為:" )

     Source.fromFile("test.txt").foreach{

       print

     }

   }

 }