代码优于描述

七、集合概况


1、集合分类

(1)scala集合按照是否可变分为可变Mutable和不可变Immutable

(2)scala集合按类型分为

  • 序列
  • set
  • map

(3)序列

通用集合

Immutable不可变Mutable可变
Indexed索引VectorArrayBuffer
链表ListListBuffer

主要不可变集合scala.collection.immutable

索引序列链表序列描述
List单链表
Queue队列
Range整数值范围
Stack
Stream类似于链表,lazy特性
Stringjava String
Vector可索引序列

主要可变集合scala.collection.mutable

索引序列链表序列描述
Array依赖java数组实现,元素可变,大小不可变
ArrayBuffer数组实现
ArrayStack数组实现栈
DoubleLinkedList双向链表
LinkedList可变单链表
ListBuffer
MutableList
Queue队列
Stack
StringBuilderjava里StringBuilder

(4)Map

不可变可变描述
HashMap
LinkedHashMap
ListMap
Map
SortedMap
TreeMap红黑树实现
WeakHashMapjava.util.WeakHashMap的封装

(5)set

不可变可变描述
BitSet
HashSet
LinkedHashSet
ListSet
TreeSet
Set
SortedSet

(6)其他

描述
Enumeration一个包含常数值的有限集合
Iterator迭代器
Option包含一个或零个元素的集合
Tuple元组,支持异构元素的集合,最多支持22个元素

2、集合方法

(1)集合方法分类

  • 过滤方法
    • collect, diff, distinct, drop, dropWhile, filter, filterNot, find, foldLeft, foldRight, head, headOption, init, intersect, last, lastOption, reduceLeft, reduceRight, remove, slice, tail, take, takeWhile, and union.
  • 转换方法
    • +, ++, −, −−, diff, distinct, collect, flatMap, map, reverse, sortWith, takeWhile, zip, and zipWithIndex.
  • 分组方法
    • groupBy, partition, sliding, span, splitAt, and unzip
  • 信息和数学方法
    • canEqual, contains, containsSlice, count, endsWith, exists, find, forAll, hasDefiniteSize, indexOf, indexOfSlice, indexWhere, isDefinedAt, isEmpty, lastIndexOf, lastIndexOfSlice, lastIndexWhere, max, min, nonEmpty, product, segmentLength, size, startsWith, sum.
  • 其他
    • par, view, flatten, foreach, mkString.

以下列表说明

  • c 代表集合
  • f 代表函数
  • p 代表谓词(返回Boolean的函数)
  • n 代表数字
  • op代表简单操作(通常是一个简单函数)

(2)遍历集合常用方法

方法描述
c collect f集合c中每一个元素通过偏函数f返回值构成一个新集合
c count p对满足谓词条件的元素计数
c1 diff c2返回c1中c2中没有的元素
c drop n返回集合去掉前n个元素的集合
c dropWhile p返回移除满足谓词p最长前缀的集合,去掉返回第一个false之前的元素
c exists p如果元素每个元素都满足p,则返回true,否则false
c filter p返回p为true的所有元素
c filterNot p返回p为false的所有元素
c find p返回第一个满足p的元素的Option否则返回None
c flatten将两层list展开一层
c flatMap对每一个元素做map,然后执行flatten
c foldLeft(z)(op)将操作应用于上一次执行的结果和当前元素,z和第一个元素操作,从左到右返回类型和z相同
c foldRight(z)(op)类似上,从右到左
c forAll p如果所有元素都满足p则返回true,否则返回false
c foreach fforeach
c groupBy f把集合归类成Map,根据f返回值作为key,同一个key的元素的集合作为value
c hasDefiniteSize测试元素是否有限
c head返回集合第一个元素,如果集合为空抛出 NoSuchElementException
c headOption返回Option
c init返回出去最后一个元素的集合,集合为空抛出UnsupportedOperationException
c1 intersect c2返回连个集合的交集
c isEmpty是否为空
c last返回最后一个元素,如果集合为空抛出 NoSuchElementException
c lastOption返回最后一个元素的Option
c map f函数f应用于每一个元素返回值的集合
c max返回最大
c min返回最小
c nonEmpty非空返回true
c par返回集合的并行实现,创建在新的线程中??
c partition p根据谓词返回两个集合的元组
c product返回所有元素的乘积
c reduceLeft op类似于foldLeft,从第一个元素开始
c reduceRight op类似于foldRight,从最后一个元素开始
c reverse集合倒序
c size集合的大小
c slice(from, to)返回from到to的间隔,区间为[from,to)
c sortWith f返回按照函数f的排序
c span p返回 c.takeWhile(p) 和 c.dropWhile(p)的并集
c splitAt在n位置拆分一个集合,返回一个由两个集合组成的元组
c sum返回集合所有元素的和
c tail返回除第一个元素外的其他元素组成的集合
c take n返回前n个元素的结合
c takeWhile p返回为true时的集合元素,false时停止
c1 union c2返回两个集合的并集
c unzip??
c view返回集合的一个非严格lazy视图
c1 zip c2按对匹配, 返回(c1(0),c2(0)),(c1(1),c2(1))…
c zipWithIndex按照下标遍历集合,返回一个元组集合

(3)可变集合中常用操作符

操作符 (方法)描述
c += x把元素x添加到元素c
c += (x,y,z)把x,y,z添加到元素c
c1 ++= c2把c2元素添加到c1中
c −= x从集合c中删除元素x
c −= (x,y,z)从集合c中删除x,y,z
c1 −−= c2从c1中删除c2中的所有元素
c(n) = x将值x赋给c(n)
c clear清空所有元素
c remove n删除位置为n的元素
c.remove(n, len)从n位置删除len长度的元素

(4)不可变集合中常用操作符

操作符 (方法)描述
c1 ++ c2c2附加到c1中创造新的集合
c :+ e把e附加到c中,并创建新元素
e +: c将元素e插到c的首部返回一个新集合
e :: list同上,在List有用
c drop n
c dropWhile p
c filter p
c filterNot p
c head
c tail
c take n
c takeWhile p见上

(5)map方法

不可变map方法

操作符 (方法)描述
m - k删除key后map
m - (k1, k2, k3)返回删除k1,k2,k3的map
m – c删除序列内的key

可变map方法

操作符 (方法)描述
mm += (k -> v)把k->v添加到map中
mm += (k1 -> v1, k2 -> v2)
mm ++= c将集合c中的pair添加到map中
mm ++= List(3 -> “c”)
mm -= k将map中k对应的k->v删除
mm -= (k1, k2, k3)
mm –= c将集合c中的key从map中删除

map不可变和可变共有方法

操作符 (方法)描述
m(k)根据k访问v
m contains k返回是否包含k
m filter p返回满足p条件的键值
m filterKeys p返回包含匹配谓词p条件的key的map
m get k返回Option
m getOrElse(k, d)如果存在k返回v,否则返回默认值d
m isDefinedAt k包含k返回true
m keys把keys作为Iterator返回
m keyIterator把keys作为Iterator返回指向non-empty iterator
m keySet将key作为set返回
m mapValues ff函数应用map中每一个value,返回一个新map
m values把keys作为Iterator返回
m valuesIterator把keys作为Iterator返回指向non-empty iterator

3、集合的性能

前置说明

|Key |描述 | | – | ———————————— | |C |常数级| |eC |需要假设的常数时间| |aC |平均常数级| |Log |log复杂度| |L |常数级复杂度| |- |不支持此操作|

性能特点

性能

OperationDescription
head返回第一个元素
tail返回除第一个元素的集合
apply索引
update对于不可变序列的函数式更新,对可变序列的副作用更新
prepend把元素添加到序列前面
append把元素添加到序列尾部
insert在序列中任意位置插入一个元素,只能在可变中使用

set/map性能特点

setmap

OperationDescription
lookup看某个元素是否在set/map中
add将新元素添加到set/map中
remove删除一个元素
min返回最小元素

4、创建序列

(1)创建集合声明类型(类似泛型)

 val x = List[Number](1, 2.0, 33D, 400L)

(2)不可变序列最佳选择

val v = Vector("a", "b", "c")                     //> v  : scala.collection.immutable.Vector[String] = Vector(a, b, c)
//IndexedSeq的默认实现
val x = IndexedSeq(1,2,3)                         //> x  : IndexedSeq[Int] = Vector(1, 2, 3)

(3)可变序列的最佳选择

import scala.collection.mutable.ArrayBuffer
var nums = ArrayBuffer(1, 2, 3)                   //> nums  : scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3)

5、遍历集合

(1)使用foreach遍历集合

val x = Vector(1, 2, 3)                           //> x  : scala.collection.immutable.Vector[Int] = Vector(1, 2, 3)
x.foreach((i: Int) => println(i))                 //> 1
                                                  //| 2
                                                  //| 3

(2)for遍历

val fruits = Traversable("apple", "banana", "orange")
                                                  //> fruits  : Traversable[String] = List(apple, banana, orange)
for (f <- fruits) println(f)                      //> apple
                                                  //| banana
                                                  //| orange


//使用循环计数器
val fruits = Vector("apple", "banana", "orange")  //> fruits  : scala.collection.immutable.Vector[String] = Vector(apple, banana, o
                                                  //| range)
for (i <- 0 until fruits.size) println(s"element $i is ${fruits(i)}")
                                                  //> element 0 is apple
                                                  //| element 1 is banana
                                                  //| element 2 is orange

(3)使用zipWithIndex或则zip创建循环计数器

zipWithIndex

val fruits = Vector("apple", "banana", "orange")  //> fruits  : scala.collection.immutable.Vector[String] = Vector(apple, banana, o
                                                  //| range)

fruits.zipWithIndex.foreach{case(e,i)=>println(s"index id $i, ele is $e")}
                                                  //> index id 0, ele is apple
                                                  //| index id 1, ele is banana
                                                  //| index id 2, ele is orange

zip,指定计数器起始值

val fruits = Vector("apple", "banana", "orange")  //> fruits  : scala.collection.immutable.Vector[String] = Vector(apple, banana, o
                                                  //| range)
for ((elem, count) <- fruits.zip(Stream from 1)) {
	println(s"element $count is $elem")       //> element 1 is apple
                                                  //| element 2 is banana
                                                  //| element 3 is orange
}

(4)迭代器遍历

//类java

6、集合变换

(1)使用for/yield

val a = Array(1, 2, 3, 4, 5)                      //> a  : Array[Int] = Array(1, 2, 3, 4, 5)
for (e <- a) yield e * 2                          //> res0: Array[Int] = Array(2, 4, 6, 8, 10)

(2)使用map方法实现集合变换

val helpers = Vector("adam", "kim", "melissa")    //> helpers  : scala.collection.immutable.Vector[String] = Vector(adam, kim, meli
                                                  //| ssa)
val caps = helpers.map(e => e.capitalize)         //> caps  : scala.collection.immutable.Vector[String] = Vector(Adam, Kim, Meliss
                                                  //| a)

(3)列表扁平化

val lol = List(List(1,2), List(3,4))              //> lol  : List[List[Int]] = List(List(1, 2), List(3, 4))
val result = lol.flatten                          //> result  : List[Int] = List(1, 2, 3, 4)

(4)flatMap(f) === map(f).flatten

val bag = List("1", "2", "three", "4", "one hundred seventy five")
																								//> bag  : List[String] = List(1, 2, three, 4, one hundred seventy five)
def toInt(in: String): Option[Int] = {
	try {
		Some(Integer.parseInt(in.trim))
	} catch {
		case e: Exception => None
	}
}                                         //> toInt: (in: String)Option[Int]
bag.flatMap(toInt).sum                    //> res0: Int = 7
bag.map(toInt).flatten.sum                //> res1: Int = 7

(5)过滤、提取集合

collect, diff, distinct,
drop, dropWhile, filter, filterNot, find, foldLeft, foldRight, head,
headOption, init, intersect, last, lastOption, reduceLeft, reduceRight,
remove, slice, tail, take, takeWhile, union

(6)集合分割(groupBy,parttition)

groupBy返回map

val x = List(15, 10, 5, 8, 20, 12)        //> x  : List[Int] = List(15, 10, 5, 8, 20, 12)
val y = x.groupBy(_ > 10)                 //> y  : scala.collection.immutable.Map[Boolean,List[Int]] = Map(false -> List(10
																								//| , 5, 8), true -> List(15, 20, 12))

partition返回元组,按照true,false分组

val x = List(15, 10, 5, 8, 20, 12)        //> x  : List[Int] = List(15, 10, 5, 8, 20, 12)
val y = x.partition(_ > 10)               //> y  : (List[Int], List[Int]) = (List(15, 20, 12),List(10, 5, 8))

span返回元组,分为满足谓词的最长前缀和剩下元素两组

val x = List(15, 10, 5, 8, 20, 12)        //> x  : List[Int] = List(15, 10, 5, 8, 20, 12)
val y = x.span(_ < 20)                    //> y  : (List[Int], List[Int]) = (List(15, 10, 5, 8),List(20, 12))

x.splitAt(2)返回元组,按照位置

val x = List(15, 10, 5, 8, 20, 12)        //> x  : List[Int] = List(15, 10, 5, 8, 20, 12)
val y = x.splitAt(2)                      //> y  : (List[Int], List[Int]) = (List(15, 10),List(5, 8, 20, 12))

sliding(size, step) | sliding(size)

val nums = (1 to 5).toArray               //> nums  : Array[Int] = Array(1, 2, 3, 4, 5)
nums.sliding(2).toList                    //> res0: List[Array[Int]] = List(Array(1, 2), Array(2, 3), Array(3, 4), Array(4,
																								//|  5))
nums.sliding(2, 2).toList                 //> res1: List[Array[Int]] = List(Array(1, 2), Array(3, 4), Array(5))
nums.sliding(2, 3).toList                 //> res2: List[Array[Int]] = List(Array(1, 2), Array(4, 5))

zip两个列表按照idx配对组成新的列表,unzip反之

val women = List("Kim", "Julia")                  //> women  : List[String] = List(Kim, Julia)
val men = List("Al", "Terry")                     //> men  : List[String] = List(Al, Terry)
val couples = women zip men                       //> couples  : List[(String, String)] = List((Kim,Al), (Julia,Terry))
couples.unzip                                     //> res0: (List[String], List[String]) = (List(Kim, Julia),List(Al, Terry))

(7)reduce和fold方法

(8)提取不重复元素

	val x = Vector(1, 1, 2, 3, 3, 4)          //> x  : scala.collection.immutable.Vector[Int] = Vector(1, 1, 2, 3, 3, 4)
	val y = x.distinct                        //> y  : scala.collection.immutable.Vector[Int] = Vector(1, 2, 3, 4)

(9)序列合并

  • ++=合并为可变集合
  • ++ 合并集合
  • union并集,diff相对补集,intersect交集
  • a ::: b 合并

(10)创建惰性视图view方法

(1 to 100).view                                   //> res0: scala.collection.SeqView[Int,scala.collection.immutable.IndexedSeq[Int]
                                                  //| ] = SeqView(...)

7、创建集合

(1)利用Range创建集合

Array.range(1, 5)                         //> res0: Array[Int] = Array(1, 2, 3, 4)
List.range(0, 10)                         //> res1: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
Vector.range(0, 10, 2)                    //> res2: scala.collection.immutable.Vector[Int] = Vector(0, 2, 4, 6, 8)

(2)枚举

object Margin extends Enumeration {
	type Margin = Value
	val TOP, BOTTOM, LEFT, RIGHT = Value
}

Margin.TOP                                //> res0: worksheet.Margin.Value = TOP

(3)元组

val d = ("Debi", 95)                      //> d  : (String, Int) = (Debi,95)
case class Person(name: String)
val t = (3, "Three", new Person("Al"))    //> t  : (Int, String, worksheet.Person) = (3,Three,Person(Al))
t._1                                      //> res0: Int = 3
t._3                                      //> res1: worksheet.Person = Person(Al)

val (x, y, z) = (3, "Three", new Person("Al"))
																								//> x  : Int = 3
																								//| y  : String = Three
																								//| z  : worksheet.Person = Person(Al)

val (x1, _, _) = t                        //> x1  : Int = 3

val b = "AL" -> "Alabama"                 //> b  : (String, String) = (AL,Alabama)

8、集合排序

val a = List(10, 5, 8, 1, 7).sorted       //> a  : List[Int] = List(1, 5, 7, 8, 10)
val b = List("banana", "pear", "apple", "orange").sorted
																								//> b  : List[String] = List(apple, banana, orange, pear)
List(10, 5, 8, 1, 7).sortWith(_ < _)      //> res0: List[Int] = List(1, 5, 7, 8, 10)
class Person(var name: String) extends Ordered[Person] {
	override def toString = name
	def compare(that: Person) = {
		if (this.name == that.name)
			0
		else if (this.name > that.name)
			1
		else
			-1
	}
}

val ty = new Person("Tyler")              //> ty  : worksheet.Person = Tyler
val al = new Person("Al")                 //> al  : worksheet.Person = Al
val paul = new Person("Paul")             //> paul  : worksheet.Person = Paul
val dudes = List(ty, al, paul)            //> dudes  : List[worksheet.Person] = List(Tyler, Al, Paul)

dudes.sorted                              //> res1: List[worksheet.Person] = List(Al, Paul, Tyler)

9、将集合转换为字符串,mkString

val a = Array("apple", "banana", "cherry")//> a  : Array[String] = Array(apple, banana, cherry)
a.mkString                                //> res0: String = applebananacherry
a.mkString(" ")                           //> res1: String = apple banana cherry
a.mkString(", ")                          //> res2: String = apple, banana, cherry
a.mkString("[", ", ", "]")                //> res3: String = [apple, banana, cherry]

八、列表、数组、映射、集及其他


1、列表(List、ListBuffer、Stream)

链表实现,头插尾插O(1) 适合递归

(1)创建与填充列表

创建不可变列表List

// 1
scala> val list = 1 :: 2 :: 3 :: Nil
list: List[Int] = List(1, 2, 3)
// 2
scala> val list = List(1, 2, 3)
x: List[Int] = List(1, 2, 3)
// 3a
scala> val x = List(1, 2.0, 33D, 4000L)
x: List[Double] = List(1.0, 2.0, 33.0, 4000.0)
322 | Chapter 11: List, Array, Map, Set (and More)
www.it-ebooks.info
// 3b
scala> val x = List[Number](1, 2.0, 33D, 4000L)
x: List[java.lang.Number] = List(1, 2.0, 33.0, 4000)
// 4
scala> val x = List.range(1, 10)
x: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> val x = List.range(0, 10, 2)
x: List[Int] = List(0, 2, 4, 6, 8)
// 5
scala> val x = List.fill(3)("foo")
x: List[String] = List(foo, foo, foo)
// 6
scala> val x = List.tabulate(5)(n => n * n)
x: List[Int] = List(0, 1, 4, 9, 16)
// 7
scala> val x = collection.mutable.ListBuffer(1, 2, 3).toList
x: List[Int] = List(1, 2, 3)
// 8
scala> "foo".toList
res0: List[Char] = List(f, o, o)

创建可变列表ListBuffer

import scala.collection.mutable.ListBuffer
var fruits = new ListBuffer[String]()
// add one element at a time to the ListBuffer
fruits += "Apple"
fruits += "Banana"
fruits += "Orange"

(2)添加元素

val x = List(2)                                   //> x  : List[Int] = List(2)
val y = 1 +: x                                    //> y  : List[Int] = List(1, 2)
val z = 0 :: y                                    //> z  : List[Int] = List(0, 1, 2)

(3)从List或ListBuffer删除元素

List

val originalList = List(5, 1, 4, 3, 2)            //> originalList  : List[Int] = List(5, 1, 4, 3, 2)
//通过filter删除
val newList = originalList.filter(_ > 2)          //> newList  : List[Int] = List(5, 4, 3)

ListBuffer

import scala.collection.mutable.ListBuffer
val x = ListBuffer(1, 2, 3, 4, 5, 6, 7, 8, 9)
																								//> x  : scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3, 4, 5, 6,
																								//|  7, 8, 9)
//通过值删除
x -= 5                                    //> res0: worksheet.x.type = ListBuffer(1, 2, 3, 4, 6, 7, 8, 9)
x -= (2, 3)                               //> res1: worksheet.x.type = ListBuffer(1, 4, 6, 7, 8, 9)
x --= Seq(1, 2, 3)                        //> res2: worksheet.x.type = ListBuffer(4, 6, 7, 8, 9)
//通过索引删除
x.remove(0)                               //> res3: Int = 4
x.remove(1, 3)

(4)合并或连接列表

使用 ++concat:::方法

(5)使用List的lazy版本Stream

构造Stream

val s = 1#::2#::3#::Stream.empty
val s1 = (1 to 1000000000).toStream //不会爆内存

2、数组(Array、ArrayBuffer)

编译成java的数组

(1)创建和更新

创建普通数组

val a = Array(1,2,3)                              //> a  : Array[Int] = Array(1, 2, 3)

var a1:Array[String]=_
a1 = Array("apple","banana")

val a2 = Array.range(1,10)                        //> a2  : Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)

val a3 = Array.range(0,10,2)                      //> a3  : Array[Int] = Array(0, 2, 4, 6, 8)
val a4 = Array.fill(3)("foo");                    //> a4  : Array[String] = Array(foo, foo, foo)
val a5 = Array.tabulate(5)(n=>n*n)                //> a5  : Array[Int] = Array(0, 1, 4, 9, 16)
val a6 = List(1,2,3).toArray                      //> a6  : Array[Int] = Array(1, 2, 3)
val a7 = "Hello".toArray                          //> a7  : Array[Char] = Array(H, e, l, l, o)

创建可变数组ArrayBuffer

import scala.collection.mutable.ArrayBuffer
var c = ArrayBuffer[String]()                     //> c  : scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer()
c += "aa"                                         //> res0: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer(aa)
c += "bb"                                         //> res1: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer(aa, bb)
c ++=Seq("cc","dd")                               //> res2: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer(aa, bb, cc,
                                                  //|  dd)
c.append("ee","ff")

(2)删除元素

  • ArrayBuffer使用-= --= removeclear
  • Array使用过滤方法和重新赋值方法

(3)排序

  • 使用scala.util.Sorting.quickSort(fruits);
  • 使用sortedsortBysortWith

    val fruits = Array("cherry", "apple", "banana")   //> fruits  : Array[String] = Array(cherry, apple, banana)
    scala.util.Sorting.quickSort(fruits)
    println(fruits.toList);                           //> List(apple, banana, cherry)
    
    fruits.sorted                                     //> res0: Array[String] = Array(apple, banana, cherry)

(4)创建多维数组

使用Array.ofDim()//非Array独有,最多允许5维

val rows = 2                                      //> rows  : Int = 2
val cols = 3                                      //> cols  : Int = 3
val a = Array.ofDim[String](rows, cols)           //> a  : Array[Array[String]] = Array(Array(null, null, null), Array(null, null,
                                                  //| null))
a(0)(0) = "a"
a(0)(1) = "b"
a(0)(2) = "c"
a(1)(0) = "d"
a(1)(1) = "e"
a(1)(2) = "f"

a                                                 //> res0: Array[Array[String]] = Array(Array(a, b, c), Array(d, e, f))

使用数组的数组

val a = Array(Array("a", "b", "c"), Array("d", "e"))
                                                  //> a  : Array[Array[String]] = Array(Array(a, b, c), Array(d, e))

3、映射(Map)

(1)创建

创建不可变Map和可变映射区别在于导入包不同

val states = Map("AL" -> "Alabama", "AK" -> "Alaska")
                                                  //> states  : scala.collection.immutable.Map[String,String] = Map(AL -> Alabama,
                                                  //| AK -> Alaska)
var states = collection.mutable.Map[String, String]()
                                                  //> states  : scala.collection.mutable.Map[String,String] = Map()

(2)选择Map实现

类或特质描述
collection.immutable.Map默认不可变映射
collection.mutable.Map基本映射可变版本
collection.mutable.LinkedHashMap遍历元素顺序为插入顺序
collection.[mutable或immutable].ListMap基于List实现,元素插入到头部
collection.SortedMap按Key排序
collection.immutable.HashMap给予Hash查找树
查看doc文档…..

(3)添加、更新或删除元素

可变

var states = collection.mutable.Map[String, String]()
																								//> states  : scala.collection.mutable.Map[String,String] = Map()
//添加或修改
states("AK") = "Alaska"
states += ("AL" -> "Alabama")             //> res0: scala.collection.mutable.Map[String,String] = Map(AL -> Alabama, AK ->
																								//|  Alaska)
states += ("AR" -> "Arkansas", "AZ" -> "Arizona")
																								//> res1: scala.collection.mutable.Map[String,String] = Map(AZ -> Arizona, AL ->
																								//|  Alabama, AR -> Arkansas, AK -> Alaska)
states ++= List("CA" -> "California", "CO" -> "Colorado")
																								//> res2: scala.collection.mutable.Map[String,String] = Map(CO -> Colorado, AZ -
																								//| > Arizona, AL -> Alabama, CA -> California, AR -> Arkansas, AK -> Alaska)
//删除
states -= "AR"                            //> res3: scala.collection.mutable.Map[String,String] = Map(CO -> Colorado, AZ -
																								//| > Arizona, AL -> Alabama, CA -> California, AK -> Alaska)

states -= ("AL", "AZ")                    //> res4: scala.collection.mutable.Map[String,String] = Map(CO -> Colorado, CA -
																								//| > California, AK -> Alaska)
states --= List("AL", "AZ")               //> res5: scala.collection.mutable.Map[String,String] = Map(CO -> Colorado, CA -
																								//| > California, AK -> Alaska)
//
states("AK") = "Alaska, A Really Big State"

states.put("CO", "Colorado")              //> res6: Option[String] = Some(Colorado)

states.retain((k,v) => k == "AK")                //> res7: scala.collection.mutable.Map[String,String] = Map(AK -> Alaska, A Real
																								//| ly Big State)
states.remove("AK")                              //> res8: Option[String] = Some(Alaska, A Really Big State)
states.clear

不可变:使用var同样可以使用+= -=

val a = Map("AL" -> "Alabama") //> a  : scala.collection.immutable.Map[String,String] = Map(AL -> Alabama)
//添加或更新
val b = a + ("AK" -> "Alaska") //> b  : scala.collection.immutable.Map[String,String] = Map(AL -> Alabama, AK ->
//|  Alaska)
val c = b + ("AR" -> "Arkansas", "AZ" -> "Arizona")
//> c  : scala.collection.immutable.Map[String,String] = Map(AL -> Alabama, AK -
//| > Alaska, AR -> Arkansas, AZ -> Arizona)

val e = c - "AR" //> e  : scala.collection.immutable.Map[String,String] = Map(AL -> Alabama, AK -
//| > Alaska, AZ -> Arizona)
val f = e - "AZ" - "AL" //> f  : scala.collection.immutable.Map[String,String] = Map(AK -> Alaska)

var x = f; //> x  : scala.collection.immutable.Map[String,String] = Map(AK -> Alaska)
x += ("AC" -> "AC");
println(x) //> Map(AK -> Alaska, AC -> AC)

(4)访问映射的值

val states = Map("AL" -> "Alabama", "AK" -> "Alaska", "AZ" -> "Arizona")
																								//> states  : scala.collection.immutable.Map[String,String] = Map(AL -> Alabama,
																								//| AK -> Alaska, AZ -> Arizona)
val s = states.getOrElse("FOO", "No such state")
																								//> s  : String = No such state
val az1 = states.get("AZ")                //> az1  : Option[String] = Some(Arizona)
val az2 = states.get("FOO")               //> az2  : Option[String] = None
val az = states("AZ")                     //> az  : String = Arizona

//不存在会抛异常
val ac = states("AC")                     //> java.util.NoSuchElementException: key not found: AC

(5)遍历映射

val ratings = Map("Lady in the Water"-> 3.0,
 "Snakes on a Plane"-> 4.0,
 "You, Me and Dupree"-> 3.5)                      //> ratings  : scala.collection.immutable.Map[String,Double] = Map(Lady in the W
                                                  //| ater -> 3.0, Snakes on a Plane -> 4.0, You, Me and Dupree -> 3.5)

for ((k,v) <- ratings) println(s"key: $k, value: $v")
                                                  //> key: Lady in the Water, value: 3.0
                                                  //| key: Snakes on a Plane, value: 4.0
                                                  //| key: You, Me and Dupree, value: 3.5

ratings.foreach {
 case(movie, rating) => println(s"key: $movie, value: $rating")
}                                                 //> key: Lady in the Water, value: 3.0
                                                  //| key: Snakes on a Plane, value: 4.0
                                                  //| key: You, Me and Dupree, value: 3.5

ratings.foreach(x => println(s"key: ${x._1}, value: ${x._2}"))
                                                  //> key: Lady in the Water, value: 3.0
                                                  //| key: Snakes on a Plane, value: 4.0
                                                  //| key: You, Me and Dupree, value: 3.5

ratings.keys.foreach((movie) => println(movie))   //> Lady in the Water
                                                  //| Snakes on a Plane
                                                  //| You, Me and Dupree
ratings.keys.foreach(println)                     //> Lady in the Water
                                                  //| Snakes on a Plane
                                                  //| You, Me and Dupree
ratings.values.foreach((rating) => println(rating))
                                                  //> 3.0
                                                  //| 4.0
                                                  //| 3.5

(6)获取所有key或value的集合

* 使用keySet keys keysIterator方法获取所有key * 使用values valuesIterator

(7)反转键值

使用for/yield,可能会丢失数据

val reverseMap = for ((k,v) <- map) yield (v, k)

(8)测试键值存在性

val states = Map(
	"AK" -> "Alaska",
	"IL" -> "Illinois",
	"KY" -> "Kentucky")               //> states  : scala.collection.immutable.Map[String,String] = Map(AK -> Alaska,
																								//| IL -> Illinois, KY -> Kentucky)
if (states.contains("FOO")) println("Found foo") else println("No foo")
																								//> No foo

states.valuesIterator.exists(_.contains("ucky"))
																								//> res0: Boolean = true
states.valuesIterator.exists(_.contains("yucky"))
																								//> res1: Boolean = false

(9)过滤键值

var x = collection.mutable.Map(1 -> "a", 2 -> "b", 3 -> "c")
																								//> x  : scala.collection.mutable.Map[Int,String] = Map(2 -> b, 1 -> a, 3 -> c)
x.retain((k, v) => k > 1)                 //> res0: scala.collection.mutable.Map[Int,String] = Map(2 -> b, 3 -> c)
x.transform((k, v) => v.toUpperCase)      //> res1: scala.collection.mutable.Map[Int,String] = Map(2 -> B, 3 -> C)

val y = x.filterKeys(_ > 2)               //> y  : scala.collection.Map[Int,String] = Map(3 -> C)

var m = Map(1 -> "a", 2 -> "b", 3 -> "c") //> m  : scala.collection.immutable.Map[Int,String] = Map(1 -> a, 2 -> b, 3 -> c
																								//| )
m.filter((t) => t._1 > 1)                 //> res2: scala.collection.immutable.Map[Int,String] = Map(2 -> b, 3 -> c)
m.take(2)                                 //> res3: scala.collection.immutable.Map[Int,String] = Map(1 -> a, 2 -> b)

(10)排序

//默认存储无序的无法排序
val grades = Map("Kim" -> 90,
	"Al" -> 85,
	"Melissa" -> 95,
	"Emily" -> 91,
	"Hannah" -> 92)                   //> grades  : scala.collection.immutable.Map[String,Int] = Map(Hannah -> 92, Mel
																								//| issa -> 95, Kim -> 90, Emily -> 91, Al -> 85)

import scala.collection.immutable.ListMap
ListMap(grades.toSeq.sortBy(_._1): _*)    //> res0: scala.collection.immutable.ListMap[String,Int] = Map(Al -> 85, Emily -
																								//| > 91, Hannah -> 92, Kim -> 90, Melissa -> 95)

ListMap(grades.toSeq.sortWith(_._1 < _._1): _*)
																								//> res1: scala.collection.immutable.ListMap[String,Int] = Map(Al -> 85, Emily -
																								//| > 91, Hannah -> 92, Kim -> 90, Melissa -> 95)
ListMap(grades.toSeq.sortWith(_._1 > _._1): _*)
																								//> res2: scala.collection.immutable.ListMap[String,Int] = Map(Melissa -> 95, Ki
																								//| m -> 90, Hannah -> 92, Emily -> 91, Al -> 85)
ListMap(grades.toSeq.sortBy(_._2): _*)    //> res3: scala.collection.immutable.ListMap[String,Int] = Map(Al -> 85, Kim ->
																								//| 90, Emily -> 91, Hannah -> 92, Melissa -> 95)
ListMap(grades.toSeq.sortWith(_._2 < _._2): _*)
																								//> res4: scala.collection.immutable.ListMap[String,Int] = Map(Al -> 85, Kim ->
																								//| 90, Emily -> 91, Hannah -> 92, Melissa -> 95)
ListMap(grades.toSeq.sortWith(_._2 > _._2): _*)
																								//> res5: scala.collection.immutable.ListMap[String,Int] = Map(Melissa -> 95, Ha
																								//| nnah -> 92, Emily -> 91, Kim -> 90, Al -> 85)

//TODO 看书_*

关于_*

  • ListMap构造函数需要传入一个可变参数的2元元组
  • sortWithsortBy返回一个序列,内容为2元元组
  • _*目的将元组拆分为2元元组的可变参数

(11)找到最大键或值

val grades = Map("Al" -> 80, "Kim" -> 95, "Teri" -> 85, "Julia" -> 90)
																								//> grades  : scala.collection.immutable.Map[String,Int] = Map(Al -> 80, Kim -> 9
																								//| 5, Teri -> 85, Julia -> 90)
grades.keysIterator.max                   //> res0: String = Teri
grades.max                                //> res1: (String, Int) = (Teri,85)

grades.valuesIterator.max                 //> res2: Int = 95
grades.keysIterator.reduceLeft((x, y) => if (x.length > y.length) x else y)
																								//> res3: String = Julia

4、集(Set)

(1)添加元素

可变集

  • 使用+= ++= add

不可变

  • 使用+ ++

(2)删除元素

可变集

  • 使用-= --=
  • 使用retain clear remove方法

不可变集

  • 使用 - --
  • 使用filter take方法

(3)使用可排序集

  • 使用SortedSet

    val s = scala.collection.SortedSet("cherry", "kiwi", "apple")
    																								//> s  : scala.collection.SortedSet[String] = TreeSet(apple, cherry, kiwi)

5、队列

6、栈

7、Range

九、文件


1、打开并读取文件

简要写法:适用于scala脚本,文件不会关闭,随jvm关闭而关闭

import scala.io.Source
val fileName = "d:/test.txt"              //> fileName  : String = d:/test.txt

val buffer = Source.fromFile(fileName)    //> buffer  : scala.io.BufferedSource = non-empty iterator

for(line<-buffer.getLines()){
	println(line)                     //> Line1
																								//| Line2
}

buffer.mkString                           //> res0: String = ""


//getLine返回一个迭代器

自动关闭资源

def using[A<:{def close():Unit}, B](resource: A)(f:A=>B):B = {
	try{
		f(resource)
	} finally {
		resource.close()
	}
}                                         //> using: [A <: AnyRef{def close(): Unit}, B](resource: A)(f: A => B)B

val fileName = "d:/test.txt"              //> fileName  : String = d:/test.txt
val buffer = Source.fromFile(fileName)    //> buffer  : scala.io.BufferedSource = non-empty iterator

using(buffer)(_.mkString);                //> res0: String = "Line1
																								//| Line2
																								//| "

处理异常(用到上面的using方法)

// 将上定义 def using[A<:{def close():Unit}, B](resource: A)(f:A=>B):B

def readTextFile(fileName:String):Option[List[String]] = {
	try{
		val lines = using(io.Source.fromFile(fileName))( source => {
			(for(line <- source.getLines()) yield line).toList
		})
		Some(lines)
	} catch {
		case e: Exception => None
	}
}                                         //> readTextFile: (fileName: String)Option[List[String]]


val fileName = "d:/test.txt"              //> fileName  : String = d:/test.txt

readTextFile(fileName)                    //> res0: Option[List[String]] = Some(List(Line1, Line2))

其他io.Source.fromFile方法

2、写入文本文件

使用java的PrintWriter或FileWriter

3、读写二进制文件

使用java的FileInputStream和FileOutputStream

4、将字符串封装成文本文件对象,便于测试

import scala.io.Source
val fileName = "d:/test.txt"              //> fileName  : String = d:/test.txt
val buffer = Source.fromString("""Line1
Line2
""")                                              //> buffer  : scala.io.Source = non-empty iterator


for (line <- buffer.getLines()) {
	println(line)                     //> Line1
																								//| Line2
}

5、序列化

import java.io._
// 创建一个类
@SerialVersionUID(123L)
class Stock(var symbol: String, var price: BigDecimal)
	extends Serializable {
	override def toString = f"$symbol%s is ${price.toDouble}%.2f"
}


// (1) 创建一个实例
val nflx = new Stock("NFLX", BigDecimal(85.00))
// (2) 创建文件流,将对象序列化后写入文件
val oos = new ObjectOutputStream(new FileOutputStream("/tmp/nflx"))
oos.writeObject(nflx)
oos.close
// (3) 从文件中读取对象并实例化
val ois = new ObjectInputStream(new FileInputStream("/tmp/nflx"))
val stock = ois.readObject.asInstanceOf[Stock]
ois.close
// (4) 测试对象
println(stock)

5、列出文件中目录

使用java方法

十、进程

1、执行外部命令

导入scala.sys.process

  • 使用!方法执行命令,并获取退出码
  • 使用!!方法执行命名,并获取输出
  • 使用lines方法在后台执行命令,并得到输出

使用!

scala> "pwd".!
/c/Users/xxxx
res0: Int = 0

scala> val code = "pwd".!
/c/Users/xxxx
code: Int = 0

scala> code
res2: Int = 0

scala> Process("pwd").!
/c/Users/xxxx
res3: Int = 0

scala> Seq("pwd").!
/c/Users/xxxx
res4: Int = 0

使用lines

val p = Process("pwd").lines

注意:只能执行外部命令,不能执行内建命令如cd for

2、执行外部命令并使用标准输出

scala> val result = "ipconfig".!!
result: String =
"
Windows IP 配置


无线局域网适配器 WLAN:

   媒体状态  . . . . . . . . . . . . : 媒体已断开连接
   连接特定的 DNS 后缀 . . . . . . . : workgroup

无线局域网适配器 本地连接* 2:

   媒体状态  . . . . . . . . . . . . : 媒体已断开连接
   连接特定的 DNS 后缀 . . . . . . . :

以太网适配器 以太网:

   连接特定的 DNS 后缀 . . . . . . . :
   本地链接 IPv6 地址. . . . . . . . : fe80::24c3:eb4a:ec45:2b2e%18
   IPv4 地址 . . . . . . . . . . . . : 172.19.208.233
   子网掩码  . . . . . . . . . . . . : 255.255.240.0
   默认网关. . . . . . . . . . . . . : 172.19.208.1

隧道适配器 本地连接* 11:

   连接特定的 DNS 后缀 . . . . . . . :
   IPv6 地址 . . . . . . . . . . . . : 2001:0:5ef5:79fd:3c7d:1a4d:53ec:2f16
   本地链接 IPv6 地址. . . . . . . . : fe80::3c7d:1a4d:53ec:2f16%17
   默认网关. . . . . . . . . . . . . : ::

隧道适配器 isatap.{F8C49FBC-3672-45C1-86F5-68A03FD0F370}:
...

3、其他略

十一、Actor和并发

1、Actor入门

import akka.actor.Actor
import akka.actor.ActorSystem
import akka.actor.Props
class HelloActor extends Actor {
	def receive = {
		case "hello" => println("hello back at you")
		case _ => println("huh?")
	}
}

object Main extends App {
	// 初始化一个actor系统,并命名
	val system = ActorSystem("HelloSystem")
	// 创建并开启一个actor,名字叫helloactor,是HelloActor的一个实例
	val helloActor = system.actorOf(Props[HelloActor], name = "helloactor")
	// 给actor发送两个消息
	helloActor ! "hello"
	helloActor ! "buenos dias"
	// 关闭actor系统
	system.shutdown
}

/*输出
hello back at you
huh?
*/

2、Actor之间通讯

import akka.actor._
case object PingMessage //来自ping的消息
case object PongMessage //来自Pong的消息
case object StartMessage //开始启动的消息
case object StopMessage //停止的消息


class Ping(pong: ActorRef) extends Actor {
	var count = 0 //计数器
	def incrementAndPrint { count += 1; println("ping") }
	def receive = { //回复消息
		case StartMessage => //接收到开始消息
			incrementAndPrint //计数器++,
			pong ! PingMessage //给pong发送消息
		case PongMessage =>
			incrementAndPrint
			if (count > 99) {
				sender ! StopMessage
				println("ping stopped")
				context.stop(self)
			} else {
				sender ! PingMessage
			}
		case _ => println("Ping got something unexpected.")
	}
}
class Pong extends Actor {
	def receive = {
		case PingMessage =>
			println(" pong")
			sender ! PongMessage
		case StopMessage =>
			println("pong stopped")
			context.stop(self)
		case _ => println("Pong got something unexpected.")
	}
}
object Main extends App {
	val system = ActorSystem("PingPongSystem")
	val pong = system.actorOf(Props[Pong], name = "pong")
	val ping = system.actorOf(Props(new Ping(pong)), name = "ping")
	// start the action
	ping ! StartMessage
	// commented-out so you can see all the output
	Thread.sleep(1000);
	system.shutdown
}
/*输出
ping
 pong
......
ping stopped
pong stopped
*/

3、Actor生命周期

import akka.actor._
class Kenny extends Actor {
	println("进入 Kenny 构造函数")
	override def preStart { println("kenny: preStart方法执行") }
	override def postStop { println("kenny: postStop方法执行") }
	override def preRestart(reason: Throwable, message: Option[Any]) {
		println("kenny: preRestart方法执行")
		println(s" 消息内容: ${message.getOrElse("")}")
		println(s" 原因: ${reason.getMessage}")
		super.preRestart(reason, message)
	}
	override def postRestart(reason: Throwable) {
		println("kenny: postRestart方法执行")
		println(s" 原因: ${reason.getMessage}")
		super.postRestart(reason)
	}
	def receive = {
		case ForceRestart => throw new Exception("Boom!")
		case _ => println("Kenny 收到一个消息")
	}
}
case object ForceRestart

object Main extends App {
	val system = ActorSystem("LifecycleDemo")
	val kenny = system.actorOf(Props[Kenny], name = "Kenny")
	println("发送 kenny 一个简单的字符串消息")
	kenny ! "hello"
	Thread.sleep(1000)
	println("让 kenny 重启")
	kenny ! ForceRestart
	Thread.sleep(1000)
	println("停止 kenny")
	system.stop(kenny)
	println("关闭系统")
	system.shutdown
}
/*输出
发送 kenny 一个简单的字符串消息
进入 Kenny 构造函数
kenny: preStart方法执行
Kenny 收到一个消息
让 kenny 重启
kenny: preRestart方法执行
 消息内容: ForceRestart
 原因: Boom!
kenny: postStop方法执行
进入 Kenny 构造函数
kenny: postRestart方法执行
 原因: Boom!
kenny: preStart方法执行
[ERROR] [12/05/2016 23:22:35.325] [LifecycleDemo-akka.actor.default-dispatcher-7] [akka://LifecycleDemo/user/Kenny] Boom!
java.lang.Exception: Boom!
	at Kenny$$anonfun$receive$1.applyOrElse(Main.scala:18)
	at akka.actor.Actor$class.aroundReceive(Actor.scala:484)
	at Kenny.aroundReceive(Main.scala:2)
	at akka.actor.ActorCell.receiveMessage(ActorCell.scala:526)
	at akka.actor.ActorCell.invoke(ActorCell.scala:495)
	at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:257)
	at akka.dispatch.Mailbox.run(Mailbox.scala:224)
	at akka.dispatch.Mailbox.exec(Mailbox.scala:234)
	at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
	at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
	at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
	at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

停止 kenny
关闭系统
kenny: postStop方法执行
*/
  • 构造函数:在第一个消息到来时实例化对象时调用
  • preStart:启动前调用,重启后方法postRestart调用
  • postStop:actor停止后调用,重启前方法preStart调用
  • preRestart:在发生异常后调用
  • postRestart:重启后调用postStop后,调用

启动流程 > 构造函数 -> preStart -> … -> postStop

重启流程 > preRestart -> postStop -> postRestart -> preStart

4、Actor启动

(1)主线程启动Actor

val system = ActorSystem("HelloSystem")
// 系统创建
val helloActor = system.actorOf(Props[HelloActor], name = "helloactor"

(2)从Actor启动Actor

class Parent extends Actor {
 val child = context.actorOf(Props[Child], name = "Child")
 // more code here ...
}

5、Actor停止

(1)actorSystem.stop(actor)context.stop(actor)方法,处理完消息队列的消息然后停止

import akka.actor._

class TestActor extends Actor {
	def receive = {
		case _ => println("收到一个消息")
	}
}
object Main extends App {
	val actorSystem = ActorSystem("SystemStopExample")
	val actor = actorSystem.actorOf(Props[TestActor], name = "test")
	actor ! "hello"
	// 停止
	actorSystem.stop(actor)
	actor ! "hello"
	actorSystem.shutdown
}
//有两种可能输出
/*
1、
收到一个消息
收到一个消息
2、
收到一个消息
[INFO] [12/06/2016 22:41:44.804] [SystemStopExample-akka.actor.default-dispatcher-7] [akka://SystemStopExample/user/test] Message [java.lang.String] from Actor[akka://SystemStopExample/deadLetters] to Actor[akka://SystemStopExample/user/test#500643557] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
*/

(2)传递PoisonPill消息,

import akka.actor._
class TestActor extends Actor {
	def receive = {
		case s: String => println("收到的消息: " + s)
		case _ => println("TestActor 收到一个位置消息")
	}
	override def postStop { println("TestActor::postStop 方法执行") }
}
object Main extends App {
	val system = ActorSystem("PoisonPillTest")
	val actor = system.actorOf(Props[TestActor], name = "test")
	// a simple message
	actor ! "在 PoisonPill消息之前"
	// the PoisonPill
	actor ! PoisonPill
	// these messages will not be processed
	actor ! "在 PoisonPill消息之前"
	actor ! "hello?!"
	system.shutdown
}

/*
收到的消息: 在 PoisonPill消息之前
TestActor::postStop 方法执行
[INFO] [12/06/2016 22:44:47.361] [PoisonPillTest-akka.actor.default-dispatcher-4] [akka://PoisonPillTest/user/test] Message [java.lang.String] from Actor[akka://PoisonPillTest/deadLetters] to Actor[akka://PoisonPillTest/user/test#-390700988] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
[INFO] [12/06/2016 22:44:47.361] [PoisonPillTest-akka.actor.default-dispatcher-4] [akka://PoisonPillTest/user/test] Message [java.lang.String] from Actor[akka://PoisonPillTest/deadLetters] to Actor[akka://PoisonPillTest/user/test#-390700988] was not delivered. [2] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
*/

(3)gracefulStop ??方法,设置延时关闭,如果在指定实现内未关闭将报异常

import akka.actor._
import akka.pattern.gracefulStop
import scala.concurrent.{ Await, ExecutionContext, Future }
import scala.concurrent.duration._
import scala.language.postfixOps
class TestActor extends Actor {
	def receive = {
		case _ => println("TestActor 收到消息")
	}
	override def postStop { println("TestActor: postStop方法执行") }
}

object Main extends App {
	val system = ActorSystem("GracefulStopTest")
	val testActor = system.actorOf(Props[TestActor], name = "TestActor")
	// try to stop the actor gracefully
	try {
		val stopped: Future[Boolean] = gracefulStop(testActor, 2 seconds, "stop")
		//Await.result(stopped, 3 seconds)
		for(i  1 to 10) testActor ! "xx"
		println("testActor 被停止")
	} catch {
		case e: Exception => e.printStackTrace
	} finally {
		system.shutdown
	}
}

/*
//Await.result(stopped, 3 seconds)
for(i <- 1 to 10) testActor ! "xx"
这样不会报异常
打开注释将会报异常
*/

6、Actor系统关闭

//system.shutdown ,已废弃
system.terminate //关闭

7、Actor监控子Actor死亡

(1)做法

context.watch(子Actor引用) //开启监控 case Terminated(kenny) //匹配消息

class Kenny extends Actor {
	def receive = {
		case _ => println("Kenny 收到一个消息")
	}
}
class Parent extends Actor {
	// start Kenny as a child, then keep an eye on it
	val kenny = context.actorOf(Props[Kenny], name = "Kenny")
	context.watch(kenny)
	def receive = {
		case Terminated(kenny) => println("OMG, Kenny被killed")
		case _ => println("Parent 收到一个消息")
	}
}

object Main extends App {
	val system = ActorSystem("DeathWatchTest")
	val parent = system.actorOf(Props[Parent], name = "Parent")
	// 获取kenny的引用
	val kenny = system.actorSelection("/user/Parent/Kenny")
	kenny ! PoisonPill
	Thread.sleep(5000)
	println("calling system.shutdown")
	system.terminate
}

(2)获取子Actor

val kenny = system.actorSelection("/user/Parent/Kenny")
val kenny = context.actorSelection("../Kenny")
val kenny = system.actorFor("akka://DeathWatchTest/user/Parent/Kenny")
val kenny = system.actorFor(Seq("user", "Parent", "Kenny"))
val kenny = system.actorFor(Seq("..", "Kenny"))

8、Futures实现并行计算任务

(1)简单实例会阻塞

import scala.concurrent.{ Await, Future }
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global

object Main extends App {
	def sleep(time: Long) { Thread.sleep(time) }

	// 使用 'time' 方法
	implicit val baseTime = System.currentTimeMillis
	// 2 - 创建一个 Future,相当于创建了一个新线程,主线程不会阻塞,且是call-by-name
	val f = Future {
		sleep(500)
		1 + 1
	}
	// 3 - 这会阻塞,获得结果
	val result = Await.result(f, 1 second)
	println(result)
	sleep(1000)
}

(2)使用回调不阻塞

import scala.concurrent.{ Future }
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{ Failure, Success }
import scala.util.Random
object Main extends App {

	def sleep(time: Long) { Thread.sleep(time) }

	println("开启一个计算")
	val f = Future {
		sleep(Random.nextInt(500))
		42
	}
	println("onComplete方法前")
	f.onComplete {
		case Success(value) => println(s"转到了回调,参数为 = $value")
		case Failure(e) => e.printStackTrace
	}
	// 做你剩下的工作
	println("A ..."); sleep(100)
	println("B ..."); sleep(100)
	println("C ..."); sleep(100)
	println("D ..."); sleep(100)
	println("E ..."); sleep(100)
	println("F ..."); sleep(100)
	sleep(2000)
}
/*输出为:
开启一个计算
onComplete方法前
A ...
B ...
C ...
D ...
转到了回调,参数为 = 42
E ...
F ...
*/

(3)回调方法

//同上......
	f.onComplete {
		case Success(value) => println(s"转到了回调,参数为 = $value")
		case Failure(e) => e.printStackTrace
	}

	f onSuccess {
		case result => println(s"成功的回调: $result")
	}
	f onFailure {
		case t => println(s"失败回调: ${t.getMessage}")
	}
//同上......
/*输出
开启一个计算
onComplete方法前
A ...
B ...
成功的回调: 42
转到了回调,参数为 = 42
C ...
D ...
E ...
F ...
*/

(4)创建返回Future[T]实例的方法

import scala.concurrent.{ Await, Future, future }
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{ Failure, Success }
object Main extends App {
	def sleep(time: Long) { Thread.sleep(time) }
	implicit val baseTime = System.currentTimeMillis

	def longRunningComputation(i: Int): Future[Int] = future {
		sleep(100)
		i + 1
	}
	// 不阻塞
	longRunningComputation(11).onComplete {
		case Success(result) => println(s"result = $result")
		case Failure(e) => e.printStackTrace
	}
	// keep the jvm from shutting down
	sleep(1000)
}
/*输出:
result = 12
*/

(5)运行多个任务,且有其他任务依赖他们,将所有任务连接一起

import scala.concurrent.{ Future, future }
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{ Failure, Success }
import scala.util.Random

object Cloud {
	def sleep(time: Long) { Thread.sleep(time) }
	def runAlgorithm(i: Int): Future[Int] = future {
		sleep(Random.nextInt(500))
		val result = i + 10
		println(s"从“云中”返回结果: $result")
		result
	}
}

object Main extends App {

	def sleep(time: Long) { Thread.sleep(time) }
	println("开始一组future")
	val result1 = Cloud.runAlgorithm(10)
	val result2 = Cloud.runAlgorithm(20)
	val result3 = Cloud.runAlgorithm(30)
	println("在 for-comprehension之前")
	val result = for {
		r1 <- result1
		r2 <- result2
		r3 <- result3
	} yield (r1 + r2 + r3) //将三个任务完成后的结果的操作
	println("在 onSuccess回调函数之前")
	result onSuccess {
		case result => println(s"total = $result")
	}
	println("在最后睡眠之前")
	sleep(2000) // keep the jvm alive
}
/*输出:
开始一组future
在 for-comprehension之前
在 onSuccess回调函数之前
在最后睡眠之前
从“云中”返回结果: 20
从“云中”返回结果: 30
从“云中”返回结果: 40
total = 90
*/

(6)连接器,将几个Future并行运算,并将结果连接起来

  • for
  • map
  • flatMap
  • filter
  • recover recoverWith fallbackTo提供错误处理机制

(7)给Actor发消息并等待消息回复

import akka.actor._
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.{ Await, ExecutionContext, Future }
import scala.concurrent.duration._
import scala.language.postfixOps

case object AskNameMessage

class TestActor extends Actor {
	def receive = {
		case AskNameMessage => // respond to the 'ask' request
			sender ! "Fred"
		case _ => println("that was unexpected")
	}
}

object Main extends App {
	// 创建系统
	val system = ActorSystem("AskTestSystem")
	val myActor = system.actorOf(Props[TestActor], name = "myActor")
	// (1) 询问actor方式1
	implicit val timeout = Timeout(5 seconds)
	val future = myActor ? AskNameMessage
	val result = Await.result(future, timeout.duration).asInstanceOf[String]
	println(result)
	// (2) 另一种方法
	val future2: Future[String] = ask(myActor, AskNameMessage).mapTo[String]
	val result2 = Await.result(future2, 1 second)
	println(result2)
	system.shutdown
}
/*输出:
Fred
Fred
*/

(8)使用become切换匹配函数

import akka.actor._
case object ActNormalMessage
case object TryToFindSolution
case object BadGuysMakeMeAngry
class DavidBanner extends Actor {
	import context._
	def angryState: Receive = {
		case ActNormalMessage =>
			println("Phew, I'm back to being David.")
			become(normalState)
	}
	def normalState: Receive = {
		case TryToFindSolution =>
			println("Looking for solution to my problem ...")
		case BadGuysMakeMeAngry =>
			println("I'm getting angry...")
			become(angryState)
	}
	def receive = {
		case BadGuysMakeMeAngry => become(angryState)
		case ActNormalMessage => become(normalState)
	}
}
object Main extends App {
	val system = ActorSystem("BecomeHulkExample")
	val davidBanner = system.actorOf(Props[DavidBanner], name = "DavidBanner")
	davidBanner ! ActNormalMessage // init to normalState
	davidBanner ! TryToFindSolution
	davidBanner ! BadGuysMakeMeAngry
	Thread.sleep(1000)
	davidBanner ! ActNormalMessage
	system.shutdown
}
/*输出:
Looking for solution to my problem ...
I'm getting angry...
Phew, I'm back to being David.
*/

(9)并发集合

scala> val v = Vector.range(0, 10)
v: scala.collection.immutable.Vector[Int] = Vector(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

scala> v.foreach(print)
0123456789

scala> v.par.foreach(print)
5678901234
scala> v.par.foreach(print)
0123456789

scala> v.par.foreach{ e => print(e); Thread.sleep(50) }
0516273894