1. 程式人生 > >spark之scala快速入門

spark之scala快速入門

scala和java都是在jvm之上的語言,相對來講,scala熱度比較低,其實並不是一個特別好的語言選擇。

原因倒不是因為scala本身的缺點,而是使用人群不夠多,論壇和社群不夠活躍。這就跟社交軟體一樣,大家都用微信,簡訊就沒人用了。

但是scala是寫分散式程式的一門非常方便的語言,因為scala幾乎每個物件都有map,reduce,filter等方法,這跟spark的用法簡直如出一轍。

多正規化

scala是一種多正規化的語言,這也沒啥特別的,就是既能面向過程又能面向物件,比如C++就是多正規化。

安裝

裝scala要先裝java,再裝scala。

互動式程式設計

scala支援像javascript那種互動式程式設計,在命令列輸入scala,進入互動式程式設計控制檯。

編譯

scalac 約等於 javac

打包和引包

打包有兩種,第一種和java一樣,在首行用package關鍵字。先掌握這種就行了。

引包也是用import但功能比java要強大,可以在程式碼任意位置引。

import java.awt.{Color, Font}
 
// 重新命名成員
import java.util.{HashMap => JavaHashMap}
 
// 隱藏成員
import java.util.{HashMap => _, _} //
引入了util包的所有成員,但是HashMap被隱藏了

預設情況下,Scala 總會引入 java.lang._ 、 scala._ 和 Predef._,這裡也能解釋,為什麼以scala開頭的包,在使用時都是省去scala.的。

資料型別

scala多了幾種比較傻又還是有點用的資料型別:

Unit 類似於void

Null 等於null

Nothing 是所有類的子類

Any 約等於 Object

常量和變數宣告

常量: val x:String ="a";

變數  var x:String ="a";

訪問修飾符

private ,protect,public default是public。有一些些區別,比如可靈活指定範圍 private[ClassA]表示ClassA能訪問。

運算子

基本運算子完全一致,不用特地去看。

針對集合或者是特殊物件有一些運算子,如List中(::,:::),Set中(&,++)等,運算子也可以作為方法使用。

if...else

完全一致,不用特地去看。

迴圈

終止迴圈。scala不支援break和continue關鍵字,scala2.8之後加入了 Breaks類,使用如下寫法:

// 匯入以下包
import scala.util.control._

// 建立 Breaks 物件
val loop = new Breaks;

// 在 breakable 中迴圈
loop.breakable{
    // 迴圈
    for(...){
       ....
       // 迴圈中斷
       loop.break;
   }
}

for迴圈比較好用,java感覺也是借鑑了該思想:

//1到10
for( var x <-  1 to 10 ){
   statement(s);
}

//1到9
for( var x <-  1 until 10 ){
   statement(s);
}

//雙迴圈,java裡面需要兩個for
for( a <- 1 to 3; b <- 1 to 3){
         println( "Value of a: " + a );
         println( "Value of b: " + b );
      }


//集合
for(x<- List)
{
}

//迴圈過濾 感覺不需要掌握,放在迴圈體內也可以。
      for( a <- numList
           if a != 3; if a < 8 ){
         println( "Value of a: " + a );
      }

//yield  注意for後面是大括號 用於返回滿足條件的所有a集合裡面的值,生成新集合
      var retVal = for{ a <- numList 
                        if a != 3; if a < 8
                      }yield a

方法宣告

在java中是先宣告出參再宣告入參,scala正好相反。只是思維方式不一樣。

object add{
   def addInt( a:Int, b:Int ) : Int = {
      var sum:Int = 0
      sum = a + b

      return sum
   }
}

函式宣告

函式是scala函數語言程式設計的重點,會在下一篇文章中重點介紹。

字串

scala字串是不能更新的所以對字串變數的修改會在記憶體區域建立一個新的字串物件,如果需要更新,可以用StringBuilder這個物件。

集合:

scala集合包括java中常見的那些集合(List,Set,Map),以及元組,與java不同的是,scala中的集合一般是不可變集合,修改集合的實現是建立一個新的集合。

連結串列(List)

列表的元素型別 T 可以寫成 List[T]。

構造列表的兩個基本單位是 Nil 和 ::  。 Nil 也可以表示為一個空列表。

scala的類java構造陣列辦法。

// 字串列表
val site: List[String] = List("Runoob", "Google", "Baidu")

// 整型列表
val nums: List[Int] = List(1, 2, 3, 4)

// 空列表
val empty: List[Nothing] = List()

// 二維列表
val dim: List[List[Int]] =
   List(
      List(1, 0, 0),
      List(0, 1, 0),
      List(0, 0, 1)
   )

scala特有的構造辦法如下:

// 字串列表
val site = "Runoob" :: ("Google" :: ("Baidu" :: Nil))

// 整型列表
val nums = 1 :: (2 :: (3 :: (4 :: Nil)))

// 空列表
val empty = Nil

// 二維列表
val dim = (1 :: (0 :: (0 :: Nil))) ::
          (0 :: (1 :: (0 :: Nil))) ::
          (0 :: (0 :: (1 :: Nil))) :: Nil

連線列表的操作

你可以使用 ::: 運算子或 List.:::() 方法或 List.concat() 方法來連線兩個或多個列表。例項如下:

object Test {
   def main(args: Array[String]) {
      val site1 = "Runoob" :: ("Google" :: ("Baidu" :: Nil))
      val site2 = "Facebook" :: ("Taobao" :: Nil)

      // 使用 ::: 運算子
      var fruit = site1 ::: site2
      println( "site1 ::: site2 : " + fruit )
      
      // 使用 List.:::() 方法
      fruit = site1.:::(site2)
      println( "site1.:::(site2) : " + fruit )

      // 使用 concat 方法
      fruit = List.concat(site1, site2)
      println( "List.concat(site1, site2) : " + fruit  )
      

   }
}

集合(Set)

可變集合和不可變集合。 雖然可變Set和不可變Set都有新增或刪除元素的操作,但是有一個非常大的差別。對不可變Set進行操作,會產生一個新的set,原來的set並沒有改變,這與List一樣。 而對可變Set進行操作,改變的是該Set本身,與ListBuffer類似。

import scala.collection.mutable.Set // 可以在任何地方引入 可變集合

val mutableSet = Set(1,2,3)
println(mutableSet.getClass.getName) // scala.collection.mutable.HashSet

mutableSet.add(4)
mutableSet.remove(1)
mutableSet += 5
mutableSet -= 2

println(mutableSet) // Set(5, 3, 4)

val another = mutableSet.toSet
println(another.getClass.getName) // scala.collection.immutable.Set

你可以使用 ++ 運算子或 Set.++() 方法來連線兩個集合。如果元素有重複的就會移除重複的元素。例項如下:

object Test {
   def main(args: Array[String]) {
      val site1 = Set("Runoob", "Google", "Baidu")
      val site2 = Set("Faceboook", "Taobao")

      // ++ 作為運算子使用
      var site = site1 ++ site2
      println( "site1 ++ site2 : " + site )

      //  ++ 作為方法使用
      site = site1.++(site2)
      println( "site1.++(site2) : " + site )
   }
}

對映(Map)

預設情況下 Scala 使用不可變 Map。如果你需要使用可變集合,你需要顯式的引入 import scala.collection.mutable.Map 類

// 空雜湊表,鍵為字串,值為整型
var A:Map[Char,Int] = Map()

// Map 鍵值對演示
val colors = Map("red" -> "#FF0000", "azure" -> "#F0FFFF")

注意,Map的get方法返回的物件是一個Option[String],Option表示可能為None,比如key值不存在的情況,如果不為None則是Some(value)。

Scala元組(Tuple)

元組是每個元素型別可以不一樣的List,最大的size是22。

val t = (1, 3.14, "Fred")  
val t = new Tuple3(1, 3.14, "Fred")//3是元組中元素的個數

我們可以使用 t._1 訪問第一個元素, t._2 訪問第二個元素,如下所示:

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

類(class)

scala的類和物件與java的類和物件基本上一樣。

類定義方法如下:

class Point(xc: Int, yc: Int) {
   var x: Int = xc
   var y: Int = yc

   def move(dx: Int, dy: Int) {
      x = x + dx
      y = y + dy
      println ("x 的座標點: " + x);
      println ("y 的座標點: " + y);
   }
}

物件的定義方法是用object關鍵字,和java以class名.java 命名檔案不同,scala是以類名.scala命名檔案。

介面(trait)

trait關鍵字很像java的interface,但是它能夠定義某個方法的實現。

trait Equal {
  def isEqual(x: Any): Boolean
  def isNotEqual(x: Any): Boolean = !isEqual(x)
}

和java一樣,scala只能繼承一個父類,但如果是trait就可以繼承多個,繼承的關鍵字是extends

模式匹配

scala的 x match{case:...} 對應java中的switch(x){case:...}

捕獲異常

scala的異常捕獲和java大致一致,只是在catch的時候使用了模式匹配的思想。

import java.io.FileReader
import java.io.FileNotFoundException
import java.io.IOException

object Test {
   def main(args: Array[String]) {
      try {
         val f = new FileReader("input.txt")
      } catch {
         case ex: FileNotFoundException => {
            println("Missing file exception")
         }
         case ex: IOException => {
            println("IO Exception")
         }
      } finally {
         println("Exiting finally...")
      }
   }
}

提取器:apply和unapply

提取器是從傳遞給它的物件中提取出構造該物件的引數。感覺這個玩意很雞肋。

object Test {
   def main(args: Array[String]) {
      
      //下面呼叫apply
      val x = Test(5)
      println(x)

      x match
      {
         //下面unapply 被呼叫
         case Test(num) => println(x + " 是 " + num + " 的兩倍!")
         case _ => println("無法計算")
      }

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

檔案IO

scala寫檔案操作直接用的是java的io,讀操作有自己的,總體來講比java簡單。

import java.io._

object Test {
   def main(args: Array[String]) {
      val writer = new PrintWriter(new File("test.txt" ))

      writer.write("菜鳥教程")
      writer.close()
   }
}

從螢幕讀輸入

import scala.io._
object Test {
   def main(args: Array[String]) {
      print("請輸入菜鳥教程官網 : " )
//2.11版本後。Console.readLine已廢棄
      val line = StdIn.readLine()

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

從檔案中讀內容

import scala.io.Source

object Test {
   def main(args: Array[String]) {
      println("檔案內容為:" )

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