八、scala函數式編程

1、函數式編程1java

一、介紹es6

Scala中的函數是Java中徹底沒有的概念。由於Java是徹底面向對象的編程語言,沒有任何面向過程編程語言的特性,所以Java中的一等公民是類和對象,
並且只有方法的概念,即寄存和依賴於類和對象中的方法。
Java中的方法是絕對不可能脫離類和對象獨立存在的。

而Scala是一門既面向對象,又面向過程的語言。所以在Scala中有很是好的面向對象的特性,可使用Scala來基於面向對象的思想開發大型複雜的系統和工程;
並且Scala也面向過程,所以Scala中有函數的概念。在Scala中,函數與類、對象等同樣,都是一等公民。Scala中的函數能夠獨立存在,不須要依賴任何類和對象。

Scala的函數式編程,就是Scala面向過程的最好的佐證。也正是由於函數式編程,才讓Scala具有了Java所不具有的更強大的功能和特性。

而之因此Scala一直沒有替代Java,是由於Scala以前一直沒有開發過太多知名的應用;而Java則不同,Java誕生的很是早,上個世界90年代就誕生了,
基於Java開發了大量知名的工程。並且最重要的一點在於Java如今不僅是一門編程語言,仍是一個龐大的,涵蓋了軟件開發,甚至大數據、雲計算的技術生態,
Java生態中的重要框架和系統就太多了:Spring,Lucene.ActivitisHadop等等。


二、將函數賦值給變量編程

// Scala中的函數是一等公民,能夠獨立定義,獨立存在,並且能夠直接將函數做爲值賦值給變量
// Scala的語法規定,將函數賦值給變量時,必須在函數後面加上空格和下劃線


###
scala> def sayHello(name: String) = println("Hello, " + name)
sayHello: (name: String)Unit

scala> val sayHelloFunc = sayHello _
sayHelloFunc: String => Unit = <function1>

scala> sayHelloFunc("leo")
Hello, leo


三、匿名函數閉包

// Scala中,函數也能夠不須要命名,此時函數被稱爲匿名函數。// 能夠直接定義函數以後,將函數賦值給某個變量;也能夠將直接定義的匿名函數傳入其餘函數之中
// Scala定義匿名函數的語法規則就是,(參數名: 參數類型) => 函數體
// 這種匿名函數的語法必須深入理解和掌握,在spark的中有大量這樣的語法,若是沒有掌握,是看不懂spark源碼的



###
scala> val sayHelloFunc = (name: String) => println("Hello, " + name)
sayHelloFunc: String => Unit = <function1>

scala> sayHelloFunc("jack")
Hello, jack


四、高階函數框架

// Scala中,因爲函數是一等公民,所以能夠直接將某個函數傳入其餘函數,做爲參數。這個功能是極其強大的,也是Java這種面向對象的編程語言所不具有的。
// 接收其餘函數做爲參數的函數,也被稱做高階函數(higher-order function)


###
scala> val sayHelloFunc = (name: String) => println("Hello, " + name)
sayHelloFunc: String => Unit = <function1>

scala> def greeting(func: (String) => Unit, name: String) {func(name)}
greeting: (func: String => Unit, name: String)Unit

scala> greeting(sayHelloFunc, "leo")
Hello, leo



scala> Array(1,2,3,4,5).map((num: Int) => num * num)
res3: Array[Int] = Array(1, 4, 9, 16, 25)



//高階函數的另一個功能是將函數做爲返回值
scala> def getGreetingFunc(msg: String) = (name: String) => println(msg + ", " + name)    #返回值是一個匿名函數
getGreetingFunc: (msg: String)String => Unit

scala> val greetingFuncHello = getGreetingFunc("hello")
greetingFuncHello: String => Unit = <function1>

scala> greetingFuncHello("leo")
hello, leo


五、高階函數的類型推斷編程語言

// 高階函數能夠自動推斷出參數類型,而不須要寫明類型;並且對於只有一個參數的函數,還能夠省去其小括號;若是僅有的一個參數在右側的函數體內只使用一次,
則還能夠將接收參數省略,而且將參數用_來替代
// 諸如3 * _的這種語法,必須掌握!!spark源碼中大量使用了這種語法!



###
scala> def greeting(func: (String) => Unit, name: String) {func(name)}
greeting: (func: String => Unit, name: String)Unit

scala> greeting
greeting   greetingFuncHello

scala> greeting((name) => println("Hello, " + name), "leo")
Hello, leo




scala> def triple(func: (Int) => Int) = {func(3)}
triple: (func: Int => Int)Int

scala> triple(3 * _)
res6: Int = 9

scala> triple(5 * _)
res7: Int = 15


2、函數式編程2ide

一、Scala的經常使用高階函數函數式編程

// map: 對傳入的每一個元素都進行映射,返回一個處理後的元素
scala> Array(1,2,3,4,5).map(2 * _)
res8: Array[Int] = Array(2, 4, 6, 8, 10)


// foreach: 對傳入的每一個元素都進行處理,可是沒有返回值
scala> (1 to 9).map("*" * _).foreach(println _)
*
**
***
****
*****
******
*******
********
*********


// filter: 對傳入的每一個元素都進行條件判斷,若是對元素返回true,則保留該元素,不然過濾掉該元素
scala> (1 to 20).filter(_ % 2 == 0)
res11: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)


// reduceLeft: 從左側元素開始,進行reduce操做,即先對元素1和元素2進行處理,而後將結果與元素3處理,再將結果與元素4處理,依次類推,即爲reduce;
//reduce操做必須掌握!spark編程的重點!!!
//下面這個操做就至關於1*2*3*4*5*6*7*8*9
scala> (1 to 9).reduceLeft(_ * _)
res12: Int = 362880


// sortWith: 對元素進行兩兩相比,進行排序
scala> Array(2,4,6,8,1,5).sortWith(_ < _)
res13: Array[Int] = Array(1, 2, 4, 5, 6, 8)


二、閉包函數

//閉包最簡潔的解釋:函數在變量不處於其有效做用域時,還可以對變量進行訪問,即爲閉包
scala> def getGreetingFunc(msg: String) = (name: String) => println(msg + ", " + name)
getGreetingFunc: (msg: String)String => Unit

scala> val greetingFuncHello = getGreetingFunc("hello")
greetingFuncHello: String => Unit = <function1>

scala> val greetingHi = getGreetingFunc("Hi")
greetingHi: String => Unit = <function1>

scala> greetingFuncHello("leo")
hello, leo

scala> greetingHi("leo")
Hi, leo


// 兩次調用getGreetingFunc函數,傳入不一樣的msg,並建立不一樣的函數返回
// 然而,msg只是一個局部變量,卻在getGreetingFunc執行完以後,還能夠繼續存在建立的函數之中;greetingFuncHello("leo"),調用時,值爲"hello"的msg被保留在了函數體內部,能夠反覆的使用
// 這種變量超出了其做用域,還可使用的狀況,即爲閉包
// Scala經過爲每一個函數建立對象來實現閉包,實際上對於getGreetingFunc函數建立的函數,msg是做爲函數對象的變量存在的,所以每一個函數才能夠擁有不一樣的msg
// Scala編譯器會確保上述閉包機制


三、SAM轉換大數據

// 在Java中,不支持直接將函數傳入一個方法做爲參數,一般來講,惟一的辦法就是定義一個實現了某個接口的類的實例對象,該對象只有一個方法;而這些接口都只有單個的抽象方法,也就是single abstract method,簡稱爲SAM

// 因爲Scala是能夠調用Java的代碼的,所以當咱們調用Java的某個方法時,可能就不得不建立SAM傳遞給方法,很是麻煩;可是Scala又是支持直接傳遞函數的。此時就可使用Scala提供的,在調用Java方法時,使用的功能,SAM轉換,即將SAM轉換爲Scala函數

// 要使用SAM轉換,須要使用Scala提供的特性,隱式轉換


###
import javax.swing._
import java.awt.event._

val button = new JButton("Click")
button.addActionListener(new ActionListener {
  override def actionPerformed(event: ActionEvent) {
    println("Click Me!!!")
  }
})

implicit def getActionListener(actionProcessFunc: (ActionEvent) => Unit) = new ActionListener {
  override def actionPerformed(event: ActionEvent) {
    actionProcessFunc(event)
  }
}
button.addActionListener((event: ActionEvent) => println("Click Me!!!"))


三、currying函數

// Curring函數,指的是,將原來接收兩個參數的一個函數,轉換爲兩個函數,第一個函數接收原先的第一個參數,而後返回接收原先第二個參數的第二個函數。
// 在函數調用的過程當中,就變爲了兩個函數連續調用的形式
// 在Spark的源碼中,也有體現,因此對()()這種形式的Curring函數,必須掌握!


###
scala> def sum(a: Int, b:Int) = a + b
sum: (a: Int, b: Int)Int

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



scala> def sum2(a: Int) = (b: Int) => a + b
sum2: (a: Int)Int => Int

scala> sum2(2)(2)
res18: Int = 4

scala> def sum3(a: Int)(b: Int) = a + b
sum3: (a: Int)(b: Int)Int

scala> sum3(3)(3)
res19: Int = 6


四、return

// Scala中,不須要使用return來返回函數的值,函數最後一行語句的值,就是函數的返回值。在Scala中,return用於在匿名函數中返回值給包含匿名函數的帶名函數,
並做爲帶名函數的返回值。
// 使用return的匿名函數,是必須給出返回類型的,不然沒法經過編譯


###
scala> def greeting(name: String) = {
     |   def sayHello(name: String): String = {
     |     return "Hello, " + name
     |   }
     |   sayHello(name)
     | }
greeting: (name: String)String

scala> greeting("leo")
res20: String = Hello, leo
相關文章
相關標籤/搜索