Scala 實(shí)用 Tips

1.多條件過(guò)濾

使用尾遞歸的形式對(duì)給定值和多個(gè) filter 條件來(lái)進(jìn)行過(guò)濾深啤,只要滿足其一仪缸,即可返回 true

尾遞歸條件過(guò)濾 func

def filter(key: String, conditionList: List[String], op: (String, String) => Boolean): Boolean = {
    @tailrec
    def filterBy(key: String, conditionList: List[String], index: Int, op: (String, String) => Boolean): Boolean = {
      if (index >= conditionList.length) false
      else if (op(key, conditionList(index))) true
      else filterBy(key, conditionList, index + 1, op)
    }

    filterBy(key, conditionList, 0, op)
  }

使用例子

該例子給定一個(gè) String List,然后給定多個(gè)過(guò)濾條件,只要滿足其一,即可返回 true维费。這樣判斷l(xiāng)ist中的元素是否以給定的條件開頭作為過(guò)濾條件果元。

val list = List("ab","abc","abcd")
val conditions = List("ab","ac")

list.map {
  r => 
     if (filter(r, conditions, (k, c) => k.startsWith(c))) {
         Option(r)
     } else None
}.filter(_.isDefine).map(_.get)

2.優(yōu)雅的遍歷 Map

當(dāng)我需要對(duì)集合的元素進(jìn)行轉(zhuǎn)換時(shí),自然而然會(huì)使用到map方法犀盟。
當(dāng)我們?cè)趯?duì) tuple 類型的集合或者針對(duì) Map 進(jìn)行map操作時(shí)而晒,通常更傾向于在 map 方法中使用 case 語(yǔ)句,這比直接使用_1與_2更加可讀阅畴。例如:

val languageToCount = Map("Scala" -> 10, "Java" -> 20, "Ruby" -> 5)
languageToCount map { case (_, count) => count + 1 }

然而對(duì)于上述場(chǎng)景倡怎,其實(shí)我們也可以使用collect方法:

languageToCount collect { case (_, count) => count + 1 }

效果完全相同。


給定一個(gè) Map 數(shù)據(jù)

val giveMap = Map("a"->"b","c"->"d","e"->"f","g"->"h","i"->"j")

我們一般最常用的方式如下:

giveMap.foreach {
   r =>
    println(s"key: ${r._1}, value: ${r._2}")
}

更優(yōu)雅的方式贱枣,使用 case 偏函數(shù)监署。這樣可以直觀的將 key 和 value 寫出來(lái),而不需要像上一個(gè)例子那樣以元祖的方式展現(xiàn)纽哥,更直觀和好懂钠乏。

giveMap.foreach {
   case (key,value) =>
    println(s"key: $key, value: $value")
}

還有一種不常用的遍歷方式

//However it requires explicit type annotations.
giveMap.map(((k: String, v: String) => {
     println(s"key: $key, value: $value")
}).tupled)

綜上,在我們一般 map 或者 foreach Map時(shí)春塌,采用case 偏函數(shù)的方式會(huì)更加優(yōu)雅和直觀晓避,推薦使用。

3.對(duì) Map 轉(zhuǎn)換時(shí)使用 mapValues

給定一個(gè) Map 數(shù)據(jù)如下只壳,其中的 value 為一個(gè)二元元祖俏拱,我們需要將此Map 中Value值中的時(shí)間戳去除掉,代碼如下吼句。

使用 mapValues 對(duì) value 值進(jìn)行處理

val giveMap = Map("a" → (5L, "b"), "c" → (1L, "d"), "e" → (8L, "f"), "g" → (4L, "h"))
//一步搞定
val result: Map[String, String] = giveMap.mapValues(_._2)

4.反轉(zhuǎn)一個(gè)已經(jīng)排好序的 Set

Set 沒有 reverse 方法锅必,因此需要我們自己來(lái)進(jìn)行反轉(zhuǎn)

優(yōu)雅的方式如下

//創(chuàng)建 sortedSet 返回值應(yīng)該從小到達(dá)拍好
val value = SortedSet(1, 2, 3, 5, 4, 8, 7, 2, 9)
//轉(zhuǎn)為Int,并進(jìn)行反轉(zhuǎn)
val result = value.foldLeft(List[Int]())((x, y) => y :: x)

5. Par 并行化集合 transfer

使用 par 后命辖,scala 中的集合遍歷會(huì)并行進(jìn)行况毅,這樣如果在需要并行遍歷和處理的業(yè)務(wù)上就能比較簡(jiǎn)單的使用 par 來(lái)解決分蓖,而不需要復(fù)雜的 future 的編程模型

def test3(): Unit = {
    val costMap = Map("1" -> Task("1", 1), "2" -> Task("2", 2), "3" -> Task("3", 3))

    val begin = System.currentTimeMillis()
    
//在這里進(jìn)行 map 操作之前 加入 par 并行化遍歷
    val listOfResults: List[String] = costMap.par.map {
      case (x, task) => {
        Thread.sleep(task.cost * 1000)
        task.name
      }
    }.toList
    println(s"結(jié)果耗時(shí): ${System.currentTimeMillis() - begin}")
    
    listOfResults foreach println

  }

我們比對(duì)一下沒有 par 和有 par 操作的結(jié)果耗時(shí)

有 par 結(jié)果耗時(shí): 3081ms
普通遍歷結(jié)果耗時(shí): 6009ms

總結(jié):par 并行化遍歷可以將集合中的元素遍歷并行化尔艇,整體處理時(shí)間由最長(zhǎng)的一個(gè)元素遍歷時(shí)間而決定,比如上例中的最大任務(wù)是睡眠3s么鹤,則最終遍歷時(shí)間就在3s左右终娃。

6. Future

1.阻塞等待一個(gè) Future

阻塞等待一個(gè) Future,Scala 如果要及時(shí)獲取到 Future結(jié)果,變異步為同步時(shí)蒸甜,則采用下面這種方法棠耕。注意 import 相關(guān)包

package com.maple.scala.feature

import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.language.postfixOps
/**
  * Copyright (c) 2018 XiaoMi Inc. All Rights Reserved.
  * Authors: Maple <leihuazhe@xiaomi.com> on 19-2-21 17:23
  */
object FutureAwait {
  def main(args: Array[String]): Unit = {
    val res = Future {
      Thread.sleep(2000)
      println("----process message end ----")
      "我是結(jié)果"
    }
    println("future 在執(zhí)行,程序繼續(xù)執(zhí)行")

    //核心代碼
    val result = Await.result(res,5 second)

    println(s"返回結(jié)果 $result")
  }
}

2. List[Future[T]] -> Future[List[T]]

如果我們?cè)谶M(jìn)行遍歷操作時(shí)柠新,每一行都返回一個(gè) Future窍荧,這樣我們整個(gè)操作最終會(huì)形成一個(gè) List 的 future 集合,這時(shí)我們需要反轉(zhuǎn)為 Future 的 list恨憎,只存在一個(gè) Future 比較好處理結(jié)果蕊退。

def test1(): Unit = {

    val costMap = Map("1" -> Task("1", 1), "2" -> Task("2", 2), "3" -> Task("3", 3))
    val begin = System.currentTimeMillis()

    val listOfFutures: Seq[Future[String]] = costMap.map {
      case (x, task) => {
        Future {
          Thread.sleep(task.cost * 1000)
          task.name
        }
      }
    }.toList

    val futureOfList:Future[List[String]] = Future.sequence(listOfFutures)

    futureOfList onComplete {
      case Success(x) => {
        val end = System.currentTimeMillis()
        println(s"結(jié)果 $x, 耗時(shí): ${end - begin}")
      }
      case Failure(ex) => println("Failed !!! " + ex)
    }

    Thread.sleep(Long.MaxValue)
  }

7.符號(hào) @ 的用法 (scala symbol @ meaning)

The effect of the @ operator is to alias the value matched on the left to the name on the right for the match.

@運(yùn)算符的作用是將@后面的值賦值給@前面的這個(gè)對(duì)象郊楣,類似于一種 alias的方法

例如:

 def test(): Unit = {
        val p = Option(2)

        p match {
            case x@Some(_) ? println(x) //Some(2)
            case None ? println("None")
        }
}    

上面的運(yùn)算符 x@Some(_) 是將后面的值 Some(_) 賦值給了 x,所以 x 的值為 Some(2)

再比如下面幾個(gè)例子:

def test(): Unit = {
        val d@(c@Some(a), Some(b)) = (Some(1), Some(2))
        
        println(s"a: $a, b: $b, c: $c, d: $d")
        //值分別為:   a: 1, b: 2, c: Some(1), d: (Some(1),Some(2))

        (Some(1), Some(2)) match {
            case d@(c@Some(a), Some(b)) => {
                println(a, b, c, d)
               //值分別為:   1,2,Some(1),(Some(1),Some(2))
            }
        }
 
        for (x@Some(y) <- Seq(None, Some(1))) {
              println(x, y)
              //值分別為(Some(1),1)
        }
    
        val List(x, xs@_*) = List(1, 2, 3)
        println(x, xs)
       //值分別為:(1,List(2, 3))

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瓤荔,一起剝皮案震驚了整個(gè)濱河市净蚤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌输硝,老刑警劉巖今瀑,帶你破解...
    沈念sama閱讀 211,423評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異点把,居然都是意外死亡橘荠,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,147評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門郎逃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)嗽仪,“玉大人扣囊,你說(shuō)我怎么就攤上這事。” “怎么了刻蟹?”我有些...
    開封第一講書人閱讀 157,019評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)续语。 經(jīng)常有香客問(wèn)我腻豌,道長(zhǎng),這世上最難降的妖魔是什么型宙? 我笑而不...
    開封第一講書人閱讀 56,443評(píng)論 1 283
  • 正文 為了忘掉前任撬呢,我火速辦了婚禮,結(jié)果婚禮上妆兑,老公的妹妹穿的比我還像新娘魂拦。我一直安慰自己,他們只是感情好搁嗓,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,535評(píng)論 6 385
  • 文/花漫 我一把揭開白布芯勘。 她就那樣靜靜地躺著,像睡著了一般腺逛。 火紅的嫁衣襯著肌膚如雪荷愕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,798評(píng)論 1 290
  • 那天棍矛,我揣著相機(jī)與錄音安疗,去河邊找鬼。 笑死够委,一個(gè)胖子當(dāng)著我的面吹牛荐类,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播茁帽,決...
    沈念sama閱讀 38,941評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼玉罐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼真竖!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起厌小,我...
    開封第一講書人閱讀 37,704評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤恢共,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后璧亚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體讨韭,經(jīng)...
    沈念sama閱讀 44,152評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,494評(píng)論 2 327
  • 正文 我和宋清朗相戀三年癣蟋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了透硝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,629評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡疯搅,死狀恐怖濒生,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情幔欧,我是刑警寧澤罪治,帶...
    沈念sama閱讀 34,295評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站礁蔗,受9級(jí)特大地震影響觉义,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜浴井,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,901評(píng)論 3 313
  • 文/蒙蒙 一晒骇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧磺浙,春花似錦洪囤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至呵曹,卻和暖如春款咖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背奄喂。 一陣腳步聲響...
    開封第一講書人閱讀 31,978評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留海洼,地道東北人跨新。 一個(gè)月前我還...
    沈念sama閱讀 46,333評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像坏逢,于是被迫代替她去往敵國(guó)和親域帐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子赘被,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,499評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 女孩走下第五個(gè)機(jī)器時(shí),蘭開陽(yáng)用興奮的眼神看著她肖揣。"就差一個(gè)了民假,謝謝你。"她剛要回話龙优,忽然間… 咣Q蛞臁! 第五部發(fā)出一...
    zstdid閱讀 263評(píng)論 0 3
  • 人的青春就像是刺猬立起刺一般 刺傷擁抱你的人 柔軟的身體在刺下酣然入睡 毫不知情 擁抱你的人卻滿是傷痕
    燕掩閱讀 320評(píng)論 0 0
  • 一彤断、GTD流程圖詳解 1野舶、GTD流程圖詳解 why:為什么要講GTD流程圖 GTD流程圖是幫助我們清空大腦,讓大腦...
    宗介山城分舵閱讀 947評(píng)論 0 0
  • 歡迎轉(zhuǎn)載宰衙,請(qǐng)注明出處平道,謝絕修改,更多請(qǐng)關(guān)注:載上你
    粵旅拍閱讀 302評(píng)論 0 0
  • 哈嘍小伙伴們大家好供炼,由于作者好幾天沒有發(fā)生存特訓(xùn)了啊一屋,別人都在催我:“怎么還不發(fā)!我想看啊袋哼,快發(fā)奥降怼!”所以今天先嬉,我...
    浮月山人閱讀 245評(píng)論 4 6