最基本的练习~:
使用伴生对象:
object holder{ class Foo{ private var x = 5} object Foo{def im_in_yr_foo(f: Foo) = f.x} } import holder.Foo val x = new Foo Foo.im_in_yr_foo(x)
基本的会话: Scala的if块是个表达式。在Java中,达到类似的目的就是这种代码: String x = true ? "true string" : "false string" Scala中没有?:的语法
if(true) 5 else "hello"
if(false) 5 else "hello"
方法和模式匹配
在JAVA编程时,有个常用的实践是每个方法只有一个返回点。每个方法的最后一行都会是个retrun语句。
def createErrorMessage(errorCode : Int):String = { var result : String = _ errorCode match { case 1 => result = "Network Failure" case 2 => result = "..." case 3 m=> result = "..." } return result; }
使用模式匹配提供的面向表达式语法改进代码: (result改为了 val类型,模式匹配能够判断唯一的值和类型)
def createErrorMessage(errorCode : Int):String = { val result = errorCode matchj{ case 1 => "NewWork Failure" case 2 =>"..." case 3 =>"..." } return result }
最终改进结果 模式匹配是这个方法唯一一个语句,而它返回个字符串类型的表达式- -
def createErrorMessage(errorCode : Int) : String = errorCode match{ case 1 => "NewWork Failuer: case 2 = > "....." case _ = >"....." }
并发:
创建个索引服务,用键值来查找特定项。服务由两个方法构成,lookUp方法根据key的索引查找值,insert方法插入新值, 基本是个键值对的映射。用加锁和可变hashMap实现,第一个currentIndex指向存放数据的可变HashMap,look和insert方法都用sychronized块包起来,表明对MutableService自身做同步。
import collection.mutable.{HashMap=>MutableHashMap} class MutableService[Key, Value] extends Service[Key, Value]{ val currentIndex = new MutableHashMap[Key,Value] def lookUp(k:key) : Option[Value] = synchronized(currentIndex.get(k)) def insert(k : key, v : value) : Unit = synchronized{ currentIndex.put(k,v) } }
把currentIndex改成一个不可变的HashMap,每次调用insert方法的时候覆盖原值。lookUp方法就可以不加任和锁了。currentIndex是个指向不变变量的可变引用,每次insert操作都会更新引用。
class ImmutableService[Key, Value] extends Service[Key,Value]{ var currentIndex = new ImmutableHashMap[Key,value] def lookUp(k : Key) : Option[Value] = currentIndex.get(k) def insert(k : key, v : Value) : Unit = synchronized{ currentIndex = currentIndex + ((k,v)) } }
Scala标准库提供了scala.Option类,鼓励大家在编程时尽量不要使用null.
Option高级技巧 (被当做集合对待)
1、创建对象或返回默认值 接收Option[String]的参数 返回指向file对象,对opiton应用map方法,在参数有值得请客下创建一个File对象。filter方法确保这个新建文件对象必须是目录。
def getTemporaryDirectory(tmpArg : Option[String] : java.io.File = { tmpArg.map( name => new java.io.File(name)). filter(_.isDirectory). getOrElse(new java.io.File( System.getProperty("java.io.tmpdir"))) }
2、foreach方法 能够仅当Option有值时才执行某段代码块。因为Option要么有零或一个值,所以代码要么执行,要么不执行。
val username : Option[String] = ... for(uname <- username) { println("User: " + uname) )
例如:Java Servlet框架对用户进行验证,如果验证成功,则安全注入HttpSession,后续的filter和servlet可以检查用户的访问权限。 Scala的惯例是不要把null或未初始化的参数传给函数。
如果多个Option都有值则执行代码 def authenticateSession(session : HttpSession, username :Option[String],password : Option[Array[Char]]) = { for(u <- usrname ;p <- password; if canAuthenticate(usrname,password)){ val privileges = privilegesFor(u) injectProvilegesIntoSession(session,privileges) } }
3、用多个可能未初始化的变量构造另一个变量 这里简单地把数据库配置参数转化为一个Option。
def createConnection(conn_url : Option[String],conn_user : Option[String],conn_pw : Option[String]) : Option[Connection] = for{ url <- conn_url user <- conn_user pw <- conn_pw }yield DriverManager.getConnection(url,user,pw)
上述代码可以通过转换函数,抽象化。
def lift3[A,B,C,D](f : Function3[A,B,C,D]) : Function3[Option[A], Option[B] (oa : Option[A], ob: Option[B], oc: Option[C]) => for(a <- oa; b<- ob; c<- oc) yield f(a,b,c) }
lift3(DriverManager.getConnection)