對於scala搞那麼多語法糖和新概念真是又愛又恨。愛的是scala引入了java一直沒有的lambda特性,這對於使用高階函數抽象來處理集合數據很是有愛(spark簡潔的RDD處理得益於此)。恨的是scala搞那麼多的新概念和語法糖。java
下面就來講說這些個語法糖和新概念:編程
1、單例對象(singleton object)
scala沒有static關鍵字,搞出了個object關鍵字來新建單例對象。在單例對象中的成員都是static的。因此要寫util類通常都要用這個東西。函數
object xxUtil { def process(xx:String):String = { xx } }
2、伴生對象和伴生類(companion object & companion class)、獨立對象(standalone object)
這兩個概念是相互的。假設有object A 和 class A 兩個同名了。這時候就能夠說:object A是class A的「伴生對象」;class A是object A的「伴生類」。當一個object B沒有同名的class B的時候,object B就叫「作獨立對象」。
伴生帶來的特權就是:它們能夠互相訪問私有成員。
class和object的區別:
一、單例對象不能用new來初始化。
二、單例對象不能帶參數。
三、單例對象在第一次調用的時候才初始化。
3、略坑的函數調用語法糖
一、神奇的點號省略。
雖然有的時候帶來必定方便,不過組合lambda特性等東西,代碼簡直就能亮瞎你的氪金狗眼。spa
//無參數 "hello" toUpperCase "hello".toUpperCase "hello".toUpperCase() //一個參數 "hello".indexOf "h" "hello" indexOf "h" //多個參數 "hello world" substring (0, 3) //所有搞在一塊兒 "hello world" substring (0, 3) toUpperCase() indexOf "h" //配合上匿名函數 Array(1,2,3) map ((i:Int)=> i+1) 1 to 3 map ((i:Int)=> i+1)
二、神奇的forscala
//這個for挺正常的吧? for(i <- 1 to 4) println(i) //這個呢! for(i <- 1 to 4 if i > 1) println(i) //這個呢!!! for(i <- 1 to 4 if i > 1; if i < 4; if i % 2 ==0) println(i)
三、神奇的花括號{}代替小括號()語法
聽說,若是函數調用只傳入一個參數,花括號能夠代替小括號(最後一個括號也能夠替換),scala粑粑不會打你屁股。設計
println("hello") println{"hello"} def xx(i:Int)(j:Int) = i+j xx(1){2} //result: 3 (xx(1)_){3} //curry化調用 (xx(1)_)(3) //curry化調用,不信你不懵 //看了上面的還沒懵?那就再來個 def xx(i:Int)(j:(Int)=>Int) = j(i) xx(1){i=> i+10} //有愛的一面 //假設我定義一個hbase的scan方法 def scan(tableName:String, cf:String, startRow:String, stopRow:String) (processFn:(Result) => Unit) = { //... } //那麼我能夠這麼天然的調用 scan(t1, cf, startRow, stopRow) { r => //TODO process result }
四、神奇的byName函數和調用
爲了讓本身定義的方法看起來和scala內建語法同樣「和諧」,搞出了一個byName參數和byName函數。code
//抄襲scala編程的例子 def myAssert(pred:()=>Boolean) = if(!pred()) throw new AssertionError myAssert(()=> 5<3) //()=> 5<3匿名函數看起來是否是不爽? //由於()=> 5<3 的調用看起來不天然。因此要將()這部分去掉。 def myAssert2(pred: => Boolean) = if(!pred) throw new AssertionError myAssert2(5<3) // 這樣看起來爽多了。
4、類型的上下界
對象
class foo[T <% A]{...} //弱上界<%。關係較弱:T可以隱式轉換爲Ordered[T] class foo[T <: A]{...} //上界<:。T必須是A的子類,A是T的類型上界。 class foo[T >: A]{...} //下界>:。T必須是A的父類,A是T類型的下界。
5、協變和逆變
+T: 協變:class Queue[+T] {}。若是C<:A,則Queue[C] <: Queue[A]
-T: 逆變 : class Queue[-T] {}。若是C<:A,則Queue[C] >: Queue[A]
6、隱式轉換
隱式轉換,是對應於顯式的轉換來講的。好比有"1234".toInt,這就是顯式的轉換,不直接調用toInt方法轉換的就是隱式轉換。ci
implicit def str2Int(s:String):Int = Integer.parseInt(s) //隱式str轉int def add(a:Int, b:Int) = a+b add("1",2) //先把"1"隱式轉換爲1,再加起來。
7、case類 (轉載者注:模板類,就是爲模式匹配設計的)
case類是什麼,case類就是一個class,但是能用來作模式匹配。因此搞出這麼個東西。。。
case類和通常類的不一樣點:
一、會有和類名同樣的工廠方法。不須要使用new來建立這個類對象。string
case class Var(name:String) val v1 = Var("peter") //和類名同樣的工廠方法
二、case類的參數列表默認是val的。
三、自動添加了toString,hashCode和equals的天然實現。
case類的最大的用途就是用來作模式匹配。
case class Var(name:String) val v1 = Var("peter") v1 match { case Var(name) => name case _ => } //匹配出name爲peter
8、模式守衛
模式守衛(pattern guard)接pattern以後,開始與if。只有模式守衛返回true纔算成功。
10 match { case n:Int if 1< n => println(n) //if到=>以前,這段爲模式守衛 case _ => }