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