scala與java之間的那些事


  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之間最根本的特征了。

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM