scala與java之間的關系,我認為可以用一句話來開頭:scala來源於java,但又高於java。
scala的設計者Martin Odersky就是一個JAVA控,這位牛人設計了javac和編寫了jdk中的通用代碼。可以說java語言本身就是Martin Odersky一步一步看着長大的。所以scala可以說打根起就和JAVA有着遠遠悠長的血緣關系。
Martin Odersky還在寫java那會,就立志開發達成一個目標:讓寫程序這樣一個基礎工作變得高效、簡單、且令人愉悅!因此可以說scala是這個目標實現過程中的一個重要里程碑。
因此可以說java是職業裝,scala就是休閑服。
scala簡練,高效。java成熟,穩重。
但是尺有所長,寸有所短。scala的簡練高效有其獨有的使用范圍:scala最適合用在算法描述領域,java適合用在指令編程領域。
scala獨有的兩招:函數式編程、簡單的並發編程.
1、scala獨有的函數式編程。
函數是scala語言中的一等公民。
一等公民的特權表現在:1.函數可以傳遞、賦值
2.scala中有嵌套函數和匿名函數
3.scala支持高階函數
4.scala支持偏應用(偏函數)
5.scala支持閉包
舉例來說:
1.可傳遞
1 def func(f:() => String) = println(f()) 2 func(() => "hi") 3 //output: hi 4 5 def foo() = "ok" 6 func(foo) 7 //output: ok 8 9 val fun = (x:Int) => print(x) 10 fun(2) 11 //output:2
2.嵌套函數
1 def foo(){ 2 def bar(){ 3 println("hi") 4 } 5 bar //exec 6 } 7 8 foo //output:hi
嵌套函數在實際中應用場景不多,其中一個場景是將遞歸函數轉為尾遞歸方式!
1 def fun1(){ 2 ..... 3 this 4 } 5 6 def fun2(){ 7 .... 8 this 9 } 10 11 //兩個函數可以如下方式使用 12 fun1().fun2()
3.匿名函數
1 lambda:函數字面量(Function literal) 2 (x:Int,y:Int) => x +y 3 參數 右箭頭 函數體 4 5 上面語句產生一段匿名函數,類型為(Int,Int) => Int 6 注意:scala中函數的參數個數為0到22個
4.高階函數
1 第一種:用函數做參數的函數。eg: 2 3 def f2(f:() => Unit) {f()} 4 5 def f1(){println(1)} 6 7 f2(f1) 8 9 f2(() => println("hi")) //傳入匿名函數 10 11 第二種:產生的結果是一個函數的函數。eg: 12 13 def hf():Int => Int = x => x +1 14 15 val fun = hf 16 17 fun(2) //output:3
5.函數柯里化
1 當函數具有多個參數時 2 def sum(x:Int,y:Int) = x + y 3 4 //參數被打散后,兩個參數分開 5 def sum2(x:Int)(y:Int) = x + y 6 7 sum2(1)(2) //output:3 8 9 scala> def first(x:Int)=(y:Int) => x+y 10 first: (x: Int)Int => Int 11 12 scala> first(1) 13 res10: Int => Int = <function1> 14 15 scala> val second=first(1) 16 second: Int => Int = <function1> 17 18 scala> second(2) 19 res11: Int = 3 20 21 函數鏈 22 把一個帶有多個參數的函數,轉換為多個只有一個參數的函數來執行 23 24 f(1)(2)(3) 相當於 ((f(1))(2))(3) 25 26 帶入參數 1執行 fa(1) 然后 帶入參數2執行 fb(2) 接着帶入參數3執行fc(3) 最后得到結果 27 28 柯里化的實際用途? 29 控制抽象,可改變代碼的書寫風格 foo(res,()=>println(res)) foo(res)(()=> println(res)) foo(res){()=> println(res)} 30 實現部分應用函數 31 scala> def log(time:java.util.Date,msg:String){println(time+msg)} 32 log: (time: java.util.Date, msg: String)Unit 33 34 scala> val log2 = log(new java.util.Date,_:String) 35 log2: String => Unit = <function1> 36 37 scala> log2("test1") 38 Mon Sep 09 23:46:15 CST 2013test1 39 40 scala> log2("test2") 41 Mon Sep 09 23:46:19 CST 2013test2 42 43 scala> log2("test3") 44 Mon Sep 09 23:46:22 CST 2013test3
6.閉包
1 在java中匿名內部類訪問局部變量是,局部變量必須聲明為final(類似閉包的實現) 2 3 scala中沒有那么麻煩: 4 5 scala> val more = 1 6 more: Int = 1 7 8 scala> val addMore = (x: Int) => x + more 9 addMore: Int => Int = <function1> 10 11 scala> addMore(10) 12 res19: Int = 11
(以上案例部分參考互聯網已公開的案例和<Programming in Scala>中部分說明)
2、scala簡單的並發編程模型
scala的並發編程采用的是actor模型,即參與者模型(國內有個通俗術語叫做觀察者模式)。
簡而言之就是每個參與者將自身的狀態變化通過某種方式廣播出去,其他參與者獲取到這種狀態變化后,再決定是否繼續參與。
scala使用精煉的函數式編程實現了actor模型,從而可以實現同一JVM單核並發,同一JVM多核並發,多個JVM之間並發,並且還可以實現某種意義上的IPC。
典型的actor編程模型如下:
1 Scala寫法1: 2 3 import actors.Actor,actors.Actor._ 4 5 class A1 extends Actor { 6 7 def act { 8 react { 9 case n:Int=>println(perfect(n)) 10 } 11 } 12 } 13 14 n to n+10 foreach (i=>{ 15 (new A1).start ! i 16 } 17 )
1 val aa = Array.fill(11)(actor { 2 react { 3 case n:Int=>println(perfect(n)) 4 } 5 } 6 ) 7 8 n to n+10 foreach (i=>aa(i-n) ! i)
兩種寫法只是區別在聲明類方式上面,一種需要顯式調用start,另外一個不需要而已。
不同JVM之間的通訊模型如下:
服務端:
1 import scala.actors._ 2 import scala.actors.Actor._ 3 import scala.actors.remote._ 4 import scala.actors.remote.RemoteActor._ 5 import org.andy.scala.actor.model.ActorDeal 6 7 class ActorServer extends Actor { 8 9 def act(){ 10 11 alive(9999) //綁定端口 12 register('ActorServer, self) //注冊服務類 13 14 15 while(true){ 16 receive { 17 case str:String =>print("There is say "+str) 18 case _=>println("There is no message ") 19 } 20 } 21 22 } 23 }
客戶端:
1 import scala.actors._ 2 import scala.actors.Actor._ 3 import scala.actors.remote._ 4 import scala.actors.remote.RemoteActor._ 5 import scala.actors.Actor 6 import org.andy.scala.actor.model.ActorDeal 7 8 class ActorClient extends Actor { 9 def act(){ 10 val actServer = select(Node("127.0.0.1", 9999), 'ActorServer) 11 //每隔5秒發送一次 12 while(true){ 13 actServer ! "Hello " 14 print("===Send Hello== ") 15 Thread.sleep(5000) 16 } 17 } 18 }
其中后的效果如下:
客戶端 client init success ===Send Hello== ===Send ad== ===Send Hello== ===Send ad== ===Send Hello== ===Send ad== ===Send Hello== ===Send ad== ===Send Hello== ===Send ad== ===Send Hello== ===Send ad== ===Send Hello== ===Send ad== ===Send Hello== ===Send ad== 服務端 server init success There is say Hello There is say Hello There is say Hello There is say Hello There is say Hello
這個模型是最簡單的不同JVM之間的通訊,我們再添加一點難度!傳遞一個對象嘗試一下:
對象定義如下:
1 class ActorDeal extends Serializable { 2 3 var msg: String = "" 4 5 def dealPrint() = { 6 println("From deal " + msg) 7 } 8 }
客戶端:
1 import scala.actors._ 2 import scala.actors.Actor._ 3 import scala.actors.remote._ 4 import scala.actors.remote.RemoteActor._ 5 import scala.actors.Actor 6 import org.andy.scala.actor.model.ActorDeal 7 8 class ActorClient extends Actor { 9 def act(){ 10 val actServer = select(Node("127.0.0.1", 9999), 'ActorServer) 11 var ad = new ActorDeal() 12 ad.msg ="WORLD" 13 while(true){ 14 actServer ! "Hello " 15 print("===Send Hello== ") 16 actServer!ad 17 println("===Send ad==") 18 Thread.sleep(5000) 19 } 20 } 21 }
高亮部分為新增的對象操作
服務端:
1 import scala.actors._ 2 import scala.actors.Actor._ 3 import scala.actors.remote._ 4 import scala.actors.remote.RemoteActor._ 5 import org.andy.scala.actor.model.ActorDeal 6 7 class ActorServer extends Actor { 8 RemoteActor.classLoader= getClass().getClassLoader() 9 10 def act(){ 11 12 alive(9999) 13 register('ActorServer, self) 14 15 16 while(true){ 17 receive { 18 case ad:ActorDeal => dealAD(ad) 19 case str:String =>print("There is say "+str) 20 case _=>println("There is no message ") 21 } 22 } 23 24 } 25 26 def dealAD(adm:ActorDeal)={ 27 println("Receive AD") 28 adm.dealPrint 29 30 } 31 }
標紅的語句是最重要的一句,如果沒有這句,scala actor將會報ClassNotFound異常。所以一定要添加上去
好,運行后的結果如下:
1 server init success 2 There is say Hello Receive AD 3 From deal WORLD 4 There is say Hello Receive AD 5 From deal WORLD 6 There is say Hello Receive AD 7 From deal WORLD
既然寫到分布式編程了,那么就再添加一點reply的東西。
下面的代碼表示的服務端如何給客戶端回復響應,請看代碼:
服務端
import scala.actors._ import scala.actors.Actor._ import scala.actors.remote._ import scala.actors.remote.RemoteActor._ import org.andy.scala.actor.model.ActorDeal class ActorServer extends Actor { RemoteActor.classLoader= getClass().getClassLoader() def act(){ alive(9999) register('ActorServer, self) while(true){ receive { case ad:ActorDeal => dealAD(ad) case str:String =>print("There is say "+str) case _=>println("There is no message ") } } } def dealAD(adm:ActorDeal)={ println("Receive AD") adm.dealPrint reply("Yet I receive") } }
高亮部分就服務端的回復語句。既然服務端有回復,那么客戶端是不是也要關心一下呢?
客戶端
import scala.actors._ import scala.actors.Actor._ import scala.actors.remote._ import scala.actors.remote.RemoteActor._ import scala.actors.Actor import org.andy.scala.actor.model.ActorDeal class ActorClient extends Actor { def act(){ val actServer = select(Node("127.0.0.1", 9999), 'ActorServer) var ad = new ActorDeal() ad.msg ="WORLD" while(true){ actServer ! "Hello " print("===Send Hello== ") var fu =actServer!!ad println("===Send ad==") var result = fu() println("===Receive=="+result) Thread.sleep(5000) } } }
首先客戶端調用“!!”就是一個等待響應的阻塞方法,這里只要收到服務端回復的確認字符串即可。
結果如下:
client init success
===Send Hello== ===Send ad==
===Receive==Yet I receive
如果我們增加點難度,回復一個對象。那又該如何處理呢?請看代碼:
服務端:
import scala.actors._ import scala.actors.Actor._ import scala.actors.remote._ import scala.actors.remote.RemoteActor._ import org.andy.scala.actor.model.ActorDeal class ActorServer extends Actor { RemoteActor.classLoader= getClass().getClassLoader() def act(){ alive(9999) register('ActorServer, self) while(true){ receive { case ad:ActorDeal => dealAD(ad) case str:String =>print("There is say "+str) case _=>println("There is no message ") } } } def dealAD(adm:ActorDeal)={ println("Receive AD") adm.dealPrint adm.msg ="I have achieve target" reply(adm) } }
我們修改了對象數據,然后reply回去。
這次客戶端會有大動作,請看:
import scala.actors._ import scala.actors.Actor._ import scala.actors.remote._ import scala.actors.remote.RemoteActor._ import scala.actors.Actor import org.andy.scala.actor.model.ActorDeal class ActorClient extends Actor { RemoteActor.classLoader = getClass().getClassLoader() def act(){ val actServer = select(Node("127.0.0.1", 9999), 'ActorServer) var ad = new ActorDeal() ad.msg ="WORLD" while(true){ actServer ! "Hello " print("===Send Hello== ") var fu =actServer!!ad println("===Send ad==") var result = fu() ********************** Thread.sleep(5000) } } }
首先一定要重置classloader,否則又會報ClassNotFound。后面result就應該是接受回復的ActorDeal對象了,但fu()返回的是any對象,又如何轉換為ActorDeal對象呢?
請點擊這里查看Scala如何類型強轉 ,具體代碼里面寫的較為詳細了。
我們看看效果:
client init success ===Send Hello== ===Send ad== From deal I have achieve target
scala其他的特點,比如:強類型,擴展性這里就不一一描述了。
上述的兩點,應該屬於scala與java之間最根本的特征了。