长久以来,习惯了写如下的Java代码:
User user = userService.get(1); if(user != null) { doStuff(); }
称之为null检查,亦有null != user的尤达式写法。
在学了Scala之后,知道了Option,改用如下写法:
Option(userService.get(1)) match { case Some(user) => doStuff() case _ => // do nothing }
最近又学会了一种新写法:
Option(userService.get(1)).foreach(user => doStuff())
对于单个null检查来说,上面的代码的足够了。foreach起的作用就是把some和none当作列表,很聪明的做法。
但是我又遇到了多个null检查,如果是Java代码的话,这么写:
User user = userService.get(1) if(user != null) { Address address = user.getAddress() if(address != null) { doStuff() } }
如果直接用Scala的Option实现上面的逻辑,可能是嵌套的match或者是函数加flatMap的形式。
其实我在写博客前遇到了另外一个问题:
val url: Option[String] = Some("http:/www.google.com/") val queryString: Option[String] = Some("q=foo") println(url.getOrElse("") + queryString.getOrElse(""))
有点代码坏味。这个问题和user.address有什么关系么?回答是两者都能用monad解决。
针对url+querystring问题我google出来的结果提到了scala中的monad思路,作为学过一点haskell但是没弄懂monad的人看过下面的代码恍然大误:
val url: Option[String] = Some("http://www.google.com/") val queryString: Option[String] = Some("q=foo") val url = for (u <- url; qs <- queryString) yield u + qs println(url)
Scala的for在这里起到了haskell中的do的作用。
回到user.address的问题,使用Scala的monad思路的代码如下:
for ( user <- Option(userService.get(1)); address <- Option(user.getAddress()) ) doStuffWithUserAndAddress();
是不是比二次null检查要清楚多了?
更多资料请google scala monad。