Functional Programming
lambda
匿名函數(至少python是叫lambda)算是FO的基本功能了。scala定義一個匿名函數按照如下格式:
object Main {
def main(args: Array[String]): Unit = {
val say = (sth: String) => {println("say: %s".format(sth))}
say("hello")
say("world")
}
}
// output:
// say: hello
// say: world
Using pattern matching
scala中,pattern matching的邏輯語句使用頻率很高,配合case class可以代替if用在一些條件判斷的情況
object Main {
def main(args: Array[String]): Unit = {
def fibonacci(in: Any): Int = {
in match {
case 0 => 0
case 1 => 1
case n: Int => fibonacci(n - 1) + fibonacci(n -2)
case _ => 0
}
}
println(fibonacci("ABC"))
println(fibonacci(3))
}
}
// output:
// 0
// 2
Case Class
Case class是特殊的class:
- Case class的創建不需要new操作符
- Case class可作爲case matching參數
object Main {
def main(args: Array[String]): Unit = {
trait Exp {}
case class Value(value: Int) extends Exp {}
case class Sum(l: Value, r: Value) extends Exp {}
case class Sub(l: Value, r: Value) extends Exp {}
def compute(exp: Exp): Int = {
exp match {
case Value(v) => v
case Sum(l, r) => compute(l) + compute(r)
case Sub(l, r) => compute(l) - compute(r)
case _ => 0
}
}
// 1 + 2
val case1 = Sum(Value(1), Value(2))
// 10 - 5
val case2 = Sub(Value(10), Value(5))
println(compute(case1))
println(compute(case2))
}
}
// output
// 3
// 5
option and check null pointer
scala加入了option的概念。option用來封裝一個值,並將java的null判斷語句封裝在其中。個人感覺,和java相比,option的引入帶來的好處是將null的判斷
由optional級別提升到了mandatory:java中可能由於代碼的不規範,有可能漏掉是否爲null的判斷,但是scala加了option,在寫代碼的時候,至少起到reminder的作用。
object Main {
def main(args: Array[String]): Unit = {
def printEnv = (name: String) => {
val getEnv = (name: String) => {
if (sys.env.contains(name)) {
Some(sys.env(name))
} else {
None
}
}
def handleEnv(name: String, opt: Option[String]): Unit = {
opt match {
case Some(h) => {
println("%s=%s".format(name, h)) // get value through case matching
println("%s get %s".format(name, opt.get)) // get value through get()
}
case None => {
println("%s is undefined".format(name)) // get none value through case matching
}
}
println("%s getOrElse %s".format(name, opt.getOrElse("none_env"))) //get value through getOrElse
}
handleEnv(name, getEnv(name))
}
printEnv("HOME")
println()
printEnv("JAVA_HOME")
}
}
// output:
// HOME is undefined
// HOME getOrElse none_env
// JAVA_HOME=C:\Program Files\Java\jdk1.8.0_101
// JAVA_HOME get C:\Program Files\Java\jdk1.8.0_101
// JAVA_HOME getOrElse C:\Program Files\Java\jdk1.8.0_101
在通過get()
拿值的時候,如果爲空,則會拋出NoSuchElementException
.
Lazy initialization
在屬性前添加lazy
可以讓該屬性在第一次使用時才被初始化。
默認情況下,是在創建對象時初始化的:
object Main {
def main(args: Array[String]): Unit = {
class Person {
val name = { // without lazy
println("init name...")
"Lilei"
}
}
val person = new Person()
println("create a person")
println("name: %s".format(person.name))
}
}
// output:
// init name...
// create a person
// name: Lilei
添加lazy
後則是使用時才初始化:
object Main {
def main(args: Array[String]): Unit = {
class Person {
lazy val name = { // without lazy
println("init name...")
"Lilei"
}
}
val person = new Person()
println("create a person")
println("name: %s".format(person.name))
}
}
// output:
// create a person
// init name...
// name: Lilei
For loop and yield:
for
循環和java基本一致,多了一些額外的增強。
Simple For
- 簡單遍歷index可以通過range的方式:
to
和until
。to
包含最後一個index,until
不包括 - 也可以通過range generator實現:
- 一個for循環申明也可以實現多個嵌套的循環
object Main {
def main(args: Array[String]):Unit = {
for (i <- 1 to 3; j <- 1 until 3) println("%d - %d".format(i, j)) // range & nested for
println()
val numbers = List(1,2,3,4,5,6)
for (i <- numbers) println("%d".format(i)) // range generator
}
}
// output:
// 1 - 1
// 1 - 2
// 2 - 1
// 2 - 2
// 3 - 1
// 3 - 2
// 1
// 2
// 3
// 4
// 5
// 6
filter & yield
另外還多了filter
和yield
的概念。
filter
即在for循環申明時可以多加些判斷條件進行過濾
yield
可以從for循環返回一個List
object Main {
def main(args: Array[String]): Unit = {
case class Person(name: String, age: Int) // case class has no need to new it
val persons: List[Person] = List(
Person("Lilei", 14),
Person("HanMeimei", 15),
Person("Lily", 16),
Person("Lucy", 17)
)
val adults = for (p<-persons if p.name startsWith "L"; if p.age >= 16) // filters
yield p
for (a <- adults) {
println("%s is an adult starts with L".format(a.name))
}
}
}
// output:
// Lily is an adult starts with L
// Lucy is an adult starts with L
Collection
scala中collecion分爲strict
和lazy
兩種,lazy
的collection中的元素只會在使用的時候被分配內存,比如range
另外collection還可以被申明爲mutable
和immutable
兩種(immutable collection也能包含mutable元素),分別在scala.collection
, scala.collection.immutable
, scala.collection.mutable
包中。
他們各自適應於不同的場景,immutable
更適合與多線程場景。建議的做法是先申明爲immutable
的,當出現需要時,再改爲mutable
的。
Collection API
filter
,MapReduce
方法可以參考:https://www.tutorialspoint.com/scala/scala_collections.htm
Collection Operatin
默認情況下申明的collection都是immutable
的,mutable collection需要導入包scala.collection.mutable
// create immutable collection
val list = List("a", "b")
val map = Map("a" -> 1, "b" -> 2)
val set = Set(1, 2)
// create mutable collection
import scala.collection.mutable._
val listBuffer = ListBuffer("a", "b")
val hashMap = HashMap("a" -> 1, "b" -> 2)
val hashSet = HashSet(1, 2)
immutable
不支持append操作,對他們的操作會返回一個新的collection:
// add opertions: the original collections change nothing
val newList = list + "c" // newList: ("a", "b", "c")
val newMap = map + ("c" -> 3)
val newSet = set + 3
// mutable
listBuffer += "c"
hashMap += ("c" -> 3)
hashSet += 3
-
+
,-
:immutable
和mutable
都支持,自身不變,返回新的結果集合 -
+=
,-=
:僅mutable
支持 - 修改操作可通過
+
重複key實現 -
:::
:連接兩個集合
val col = colA ::: colB
- Tail Recursion:
list match {
case List() => init
case head :: tail => ... // head is the first elem, tail is the rest
}
Parallel Collection
通過.par
方法可以返回當前集合的一個並行實現。
- 一般情況下,返回的都是一個copy,這會花費線性時間,並且新生成的集合和原集合的數據是不共享的。
- 但是對於
ParArray
和mutable.ParHashMap
(HashMap.par的返回類型),是會共享原數據的,所以花費的時間是固定的。
object Parallel {
def main(args: Array[String]):Unit = {
val list = List(1, 2, 3, 4)
val newList = list.par.map((e) => {e + 1})
println(newList)
}
}