寫給Java程序員的Scala入門教程

      網友投稿 794 2025-04-02

      Java 8擁有了一些初步的函數式編程能力:閉包等,還有新的并發編程模型及Stream這個帶高階函數和延遲計算的數據集合。在嘗試了Java 8以后,也許會覺得意猶未盡。是的,你會發現Scala能滿足你在初步嘗試函數式編程后那求知的欲望。 ## 安裝Scala 到Scala官方-下載:http://scala-lang.org/download/:


      scala> ```? **RELP**? 剛才我們已經啟動了Scala

      RELP,它是一個基于命令行的交互式編程環境。對于有著Python、Ruby等動態語言的同學來說,這是一個很常用和工具。但Javaer們第一次見到會覺得比較神奇。我們可以在RELP中做一些代碼嘗試而不用啟動笨拙的IDE,這在我們思考問題時非常的方便。對于Javaer有一個好消息,JDK

      9干始將內建支持RELP功能。

      ----------------------------------------------------------------------------------------------

      對于Scala常用的IDE(集成開發環境),推薦使用[IDEA for scala

      plugins](https://www.jetbrains.com/idea/)和[scala-ide](http://scala-ide.org/)。

      Scala的強大,除了它自身對多核編程更好的支持、函數式特性及一些基于Scala的第3方庫和框架(如:Akka、Playframework、Spark、Kafka……),還在于它可以無縫與Java結合。所有為Java開發的庫、框架都可以自然的融入Scala環境。當然,Scala也可以很方便的Java環境集成,比如:[**Spring**](http://spring.io/)。若你需要第3方庫的支持,可以使用[**Maven**](http://maven.apache.org/)、[**Gradle**](http://gradle.org/)、[**Sbt**](http://www.scala-sbt.org/)等編譯環境來引入。

      Scala是一個面向對象的函數式特性編程語言,它繼承了Java的面向對特性,同時又從[`Haskell`](https://www.haskell.org/)等其它語言那里吸收了很多函數式特性并做了增強。

      ## 變量、基礎數據類型

      Scala中變量不需要顯示指定類型,但需要提前聲明。這可以避免很多命名空間污染問題。Scala有一個很強大的類型自動推導功能,它可以根據右值及上下文自動推導出變量的類型。你可以通過如下方式來直接聲明并賦值。

      (注:函數式編程有一個很重要的特性:不可變性。Scala中除了變量的不可變性,它還定義了一套不可變集合`scala.collection.immutable._`。)

      `val`代表這是一個final

      variable,它是一個常量。定義后就不可以改變,相應的,使用`var`定義的就是平常所見的變量了,是可以改變的。從終端的打印可以看出,Scala從右值自動推導出了變量的類型。Scala可以如動態語言似的編寫代碼,但又有靜態語言的編譯時檢查。這對于Java中冗長、重復的類型聲明來說是一種很好的進步。

      (注:在`RELP`中,`val`變量是可以重新賦值的,這是`RELP`的特性。在平常的代碼中是不可以的。)? **基礎數據類型**

      Scala中基礎數據類型有:Byte、Short、Int、Long、Float、Double,Boolean,Char、String。和Java不同的是,Scala中沒在區分原生類型和裝箱類型,如:`int`和`Integer`。它統一抽象成`Int`類型,這樣在Scala中所有類型都是對象了。編譯器在編譯時將自動決定使用原生類型還是裝箱類型。

      **字符串**? Scala中的字符串有3種。? - 分別是普通字符串,它的特性和Java字符串一至。 -

      連線3個雙引號在Scala中也有特殊含義,它代表被包裹的內容是原始字符串,可以不需要字符轉碼。這一特性在定義正則表達式時很有優勢。 -

      還有一種被稱為“字符串插值”的字符串,他可以直接引用上下文中的變量,并把結果插入字符串中。? ```scala scala> val c2

      = '楊' c2: Char = 楊? scala> val s1 = "重慶譽存企業信用管理有限公司" s1:

      String = 重慶譽存企業信用管理有限公司? scala> val s2 =

      s"重慶譽存企業信用管理有限公司${c2}景" s2: String = 重慶譽存企業信用管理有限公司? scala>

      val s3 =

      s"""重慶譽存企業信用管理有限公司"工程師"\n${c2}景是江津人"""

      s3: String = 重慶譽存企業信用管理有限公司"工程師" 楊景是江津人? ```? ## 運算符和命名

      Scala中的運算符其實是定義在對象上的方法(函數),你看到的諸如:`3 +

      2`其實是這樣子的:`3.+(2)`。`+`符號是定義在`Int`對象上的一個方法。支持和Java一至的運算符(方法):

      (注:在Scala中,方法前的`.`號和方法兩邊的小括號在不引起歧義的情況下是可以省略的。這樣我們就可以定義出很優美的[`DSL`](https://en.wikipedia.org/wiki/Domain-specific_language))

      - `==`、`!=`:比較運算 - `!`、`|`、`&`、`^`:邏輯運算 - `>>`、`<<`:位運算

      ***注意***

      在Scala中,修正了(算更符合一般人的常規理解吧)`==`和`!=`運算符的含義。在Scala中,`==`和`!=`是執行對象的值比較,相當于Java中的`equals`方法(實際上編譯器在編譯時也是這么做的)。而對象的引用比較需要使用`eq`和`ne`兩個方法來實現。

      ## 控制語句(表達式)? Scala中支持`if`、`while`、`for comprehension`(for表達式)、`match

      case`(模式匹配)四大主要控制語句。Scala不支持`switch`和`? :`兩種控制語句,但它的`if`和`match

      case`會有更好的實現。? **`if`**

      Scala支持`if`語句,其基本使用和`Java`、`Python`中的一樣。但不同的時,它是有返回值的。

      (注:Scala是函數式語言,函數式語言還有一大特性就是:表達式。函數式語言中所有語句都是基于“表達式”的,而“表達式”的一個特性就是它會有一個值。所有像`Java`中的`?

      :`3目運算符可以使用`if`語句來代替)。? ```scala scala> if (true) "真" else

      "假" res0: String = 真? scala> val f = if (false)

      "真" else "假" f: String = 假? scala> val unit = if

      (false) "真" unit: Any = ()? scala> val unit2 = if (true)

      "真"? unit2: Any = 真 ```

      ***可以看到,`if`語句也是有返回值的,將表達式的結果賦給變量,編譯器也能正常推導出變量的類型。***`unit`和`unit2`變量的類型是`Any`,這是因為`else`語句的缺失,Scala編譯器就按最大化類型來推導,而`Any`類型是Scala中的根類型。`()`在Scala中是`Unit`類型的實例,可以看做是`Java`中的`Void`。

      **`while`**? Scala中的`while`循環語句:? ```scala while (條件) {?? 語句塊 } ```

      **`for comprehension`**

      Scala中也有`for`表達式,但它和`Java`中的`for`不太一樣,它具有更強大的特性。通常的`for`語句如下:? ```scala

      for (變量 <- 集合) {?? 語句塊 } ```

      Scala中`for`表達式除了上面那樣的常規用法,它還可以使用`yield`關鍵字將集合映射為另一個集合:? ```scala

      scala> val list = List(1, 2, 3, 4, 5) list: List[Int] = List(1, 2, 3,

      4, 5)? scala> val list2 = for (item <- list) yield item + 1 list2:

      List[Int] = List(2, 3, 4, 5, 6) ```? 還可以在表達式中使用`if`判斷:? ```scala

      scala> val list3 = for (item <- list if item % 2 == 0) yield item

      list3: List[Int] = List(2, 4) ```

      還可以做`flatMap`操作,解析2維列表并將結果攤平(將2維列表拉平為一維列表):? ```scala scala> val

      llist = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9)) llist:

      List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))

      scala> for {????? |?? l <- llist????? |?? item <- l if item % 2

      == 0????? | } yield item res3: List[Int] = List(2, 4, 6, 8) ```

      看到了,Scala中`for

      comprehension`的特性是很強大的。Scala的整個集合庫都支持這一特性,包括:`Seq`、`Map`、`Set`、`Array`……

      Scala沒有C-Like語言里的`for (int i = 0; i < 10;

      i++)`語法,但`Range`(范圍這個概念),可以基于它來實現循環迭代功能。在Scala中的使用方式如下:? ```scala

      scala> for (i <- (0 until 10)) {????? |?? println(i)????? | } 0 1

      2 3 4 5 6 7 8 9 ```? Scala中還有一個`to`方法:? ```scala scala> for (i <-

      (0 to 10)) print(" " + i)? 0 1 2 3 4 5 6 7 8 9 10 ```

      你還可以控制每次步進的步長,只需要簡單的使用`by`方法即可:? ```scala scala> for (i <- 0 to 10

      by 2) print(" " + i)? 0 2 4 6 8 10 ```? **match case**

      模式匹配,是函數式語言很強大的一個特性。它比命令式語言里的`switch`更好用,表達性更強。? ```scala scala> def

      level(s: Int) = s match {????? |?? case n if n >= 90 =>

      "優秀"????? |?? case n if n >= 80 => "良好"????? |

      case n if n >= 70 => "良"????? |?? case n if n >= 60

      => "及格"????? |?? case _ => "差"????? | } level:

      (s: Int)String? scala> level(51) res28: String = 差? scala>

      level(93) res29: String = 優秀? scala> level(80) res30: String = 良好 ```

      可以看到,模式匹配可以實現`switch`相似的功能。但與`switch`需要使用`break`明確告知終止之后的判斷不同,Scala中的`match

      case`是默認**break**的。只要其中一個`case`語句匹配,就終止之后的所以比較。且對應`case`語句的表達式值將作為整個`match

      case`表達式的值返回。

      Scala中的模式匹配還有類型匹配、數據抽取、謂詞判斷等其它有用的功能。這里只做簡單介紹,之后會單獨一個章節來做較詳細的解讀。? ## 集合

      在`java.util`包下有豐富的集合庫。Scala除了可以使用Java定義的集合庫外,它還自己定義了一套功能強大、特性豐富的`scala.collection`集合庫API。

      在Scala中,常用的集合類型有:`List`、`Set`、`Map`、`Tuple`、`Vector`等。? **List**

      Scala中`List`是一個不可變列表集合,它很精妙的使用遞歸結構定義了一個列表集合。? ```scala scala> val

      list = List(1, 2, 3, 4, 5) list: List[Int] = List(1, 2, 3, 4, 5) ```

      除了之前使用`List`object來定義一個列表,還可以使用如下方式:? ```scala scala> val list = 1 ::

      2 :: 3 :: 4 :: 5 :: Nil list: List[Int] = List(1, 2, 3, 4, 5) ```

      `List`采用前綴操作的方式(所有操作都在列表頂端(開頭))進行,`::`操作符的作用是將一個元素和列表連接起來,并把元素放在列表的開頭。這樣`List`的操作就可以定義成一個遞歸操作。添加一個元素就是把元素加到列表的開頭,List只需要更改下頭指針,而刪除一個元素就是把List的頭指針指向列表中的第2個元素。這樣,`List`的實現就非常的高效,它也不需要對內存做任何的轉移操作。`List`有很多常用的方法:

      ```scala scala> list.indexOf(3) res6: Int = 2? scala> 0 :: list

      res8: List[Int] = List(0, 1, 2, 3, 4, 5)? scala> list.reverse res9:

      List[Int] = List(5, 4, 3, 2, 1)? scala> list.filter(item => item

      == 3) res11: List[Int] = List(3)? scala> list res12: List[Int] =

      List(1, 2, 3, 4, 5)? scala> val list2 = List(4, 5, 6, 7, 8, 9) list2:

      List[Int] = List(4, 5, 6, 7, 8, 9)? scala> list.intersect(list2)

      res13: List[Int] = List(4, 5)? scala> list.union(list2) res14:

      List[Int] = List(1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9)? scala>

      list.diff(list2) res15: List[Int] = List(1, 2, 3) ```

      Scala中默認都是**Immutable

      collection**,在集合上定義的操作都不會更改集合本身,而是生成一個新的集合。這與Java集合是一個根本的區別,Java集合默認都是可變的。

      **Tuple**

      Scala中也支持**Tuple**(元組)這種集合,但最多只支持22個元素(事實上Scala中定義了`Tuple0`、`Tuple1`……`Tuple22`這樣22個`TupleX`類,實現方式與`C++

      Boost`庫中的`Tuple`類似)。和大多數語言的Tuple類似(比如:Python),Scala也采用小括號來定義元組。

      ```scala scala> val tuple3 = (1, 2, 3) tuple1: (Int, Int, Int) =

      (1,2,3)? scala> tuple3._2 res17: Int = 2? scala> val tuple2 =

      Tuple2("楊", "景") tuple2: (String, String) = (楊,景)

      ```? 可以使用`xxx._[X]`的形式來引用`Tuple`中某一個具體元素,其`_[X]`下標是從1開始的,一直到22(若有定義這么多)。

      **Set**? `Set`是一個不重復且無序的集合,初始化一個`Set`需要使用`Set`對象:? ```scala scala>

      val set = Set("Scala", "Java", "C++",

      "Javascript", "C#", "Python",

      "PHP")? set: scala.collection.immutable.Set[String] =

      Set(Scala, C#, Python, Javascript, PHP, C++, Java)? scala> set +

      "Go" res21: scala.collection.immutable.Set[String] =

      Set(Scala, C#, Go, Python, Javascript, PHP, C++, Java)? scala> set

      filterNot (item => item == "PHP") res22:

      scala.collection.immutable.Set[String] = Set(Scala, C#, Python,

      Javascript, C++, Java) ```? **Map**

      Scala中的`Map`默認是一個**HashMap**,其特性與Java版的`HashMap`基本一至,除了它是`Immutable`的:

      ```scala scala> val map = Map("a" -> "A",

      "b" -> "B") map:

      scala.collection.immutable.Map[String,String] = Map(a -> A, b ->

      B)? scala> val map2 = Map(("b", "B"),

      ("c", "C")) map2:

      scala.collection.immutable.Map[String,String] = Map(b -> B, c ->

      C) ```

      Scala中定義`Map`時,傳入的每個`Entry`(**K**、**V**對)其實就是一個`Tuple2`(有兩個元素的元組),而`->`是定義`Tuple2`的一種便捷方式。

      ```scala scala> map + ("z" -> "Z") res23:

      scala.collection.immutable.Map[String,String] = Map(a -> A, b ->

      B, z -> Z)? scala> map.filterNot(entry => entry._1 ==

      "a") res24: scala.collection.immutable.Map[String,String] =

      Map(b -> B)? scala> val map3 = map - "a" map3:

      scala.collection.immutable.Map[String,String] = Map(b -> B)

      scala> map res25: scala.collection.immutable.Map[String,String] =

      Map(a -> A, b -> B) ```? Scala的immutable

      collection并沒有添加和刪除元素的操作,其定義`+`(`List`使用`::`在頭部添加)操作都是生成一個新的集合,而要刪除一個元素一般使用

      `-` 操作直接將**Key**從`map`中減掉即可。

      (注:Scala中也`scala.collection.mutable._`集合,它定義了不可變集合的相應可變集合版本。一般情況下,除非一此性能優先的操作(其實Scala集合采用了共享存儲的優化,生成一個新集合并不會生成所有元素的復本,它將會和老的集合共享大元素。因為Scala中變量默認都是不可變的),推薦還是采用不可變集合。因為它更直觀、線程安全,你可以確定你的變量不會在其它地方被不小心的更改。)

      ## Class

      Scala里也有`class`關鍵字,不過它定義類的方式與Java有些區別。Scala中,類默認是**public**的,且類屬性和方法默認也是**public**的。Scala中,每個類都有一個**“主構造函數”**,主構造函數類似函數參數一樣寫在類名后的小括號中。因為Scala沒有像Java那樣的“構造函數”,所以屬性變量都會在類被創建后初始化。所以當你需要在構造函數里初始化某些屬性或資源時,寫在類中的屬性變量就相當于構造初始化了。

      在Scala中定義類非常簡單:? ```scala class Person(name: String, val age: Int) {

      override def toString(): String = s"姓名:$name, 年齡: $age" } ```

      默認,Scala主構造函數定義的屬性是**private**的,可以顯示指定:`val`或`var`來使其可見性為:**public**。

      Scala中覆寫一個方法必需添加:`override`關鍵字,這對于Java來說可以是一個修正。當標記了`override`關鍵字的方法在編譯時,若編譯器未能在父類中找到可覆寫的方法時會報錯。而在Java中,你只能通過`@Override`注解來實現類似功能,它的問題是它只是一個可選項,且編譯器只提供警告。這樣你還是很容易寫出錯誤的“覆寫”方法,你以后覆寫了父類函數,但其實很有可能你是實現了一個新的方法,從而引入難以察覺的BUG。

      實例化一個類的方式和Java一樣,也是使用`new`關鍵字。? ```scala scala> val me = new

      Person("楊景", 30) me: Person = 姓名:楊景, 年齡: 30? scala>

      println(me) 姓名:楊景, 年齡: 30? scala> me.name :20: error: value name is

      not a member of Person??????? me.name?????????? ^? scala> me.age

      res11: Int = 30 ```? **case class(樣本類)**? `case

      class`是Scala中學用的一個特性,像`Kotlin`這樣的語言也學習并引入了類似特性(在`Kotlin`中叫做:`data

      class`)。`case class`具有如下特性:? 1. 不需要使用`new`關鍵詞創建,直接使用類名即可 2.

      默認變量都是**public final**的,不可變的。當然也可以顯示指定`var`、`private`等特性,但一般不推薦這樣用 3.

      自動實現了:`equals`、`hashcode`、`toString`等函數 4.

      自動實現了:`Serializable`接口,默認是可序列化的 5. 可應用到**match case**(模式匹配)中 6.

      自帶一個`copy`方法,可以方便的根據某個`case class`實例來生成一個新的實例 7. ……? 這里給出一個`case

      class`的使用樣例:? ```scala scala> trait Person defined trait Person

      scala> case class Man(name: String, age: Int) extends Person defined

      class Man? scala> case class Woman(name: String, age: Int) extends

      Person defined class Woman? scala> val man = Man("楊景", 30)

      man: Man = Man(楊景,30)? scala> val woman = Woman("女人", 23)

      woman: Woman = Woman(女人,23)? scala> val manNextYear = man.copy(age =

      31) manNextYear: Man = Man(楊景,31) ```? ## object

      Scala有一種不同于Java的特殊類型,**Singleton Objects**。? ```scala object Blah {

      def sum(l: List[Int]): Int = l.sum } ```

      在Scala中,沒有Java里的**static**靜態變量和靜態作用域的概念,取而代之的是:**object**。它除了可以實現Java里**static**的功能,它同時還是一個線程安全的單例類。

      **伴身對象**

      大多數的`object`都不是獨立的,通常它都會與一個同名的`class`定義在一起。這樣的`object`稱為**伴身對象**。

      ```scala class IntPair(val x: Int, val y: Int)? object IntPair {

      import math.Ordering?? implicit def ipord: Ordering[IntPair] =

      Ordering.by(ip => (ip.x, ip.y)) } ```? ***注意***

      寫給Java程序員的Scala入門教程

      **伴身對象**必需和它關聯的類定義定義在同一個**.scala**文件。

      伴身對象和它相關的類之間可以相互訪問受保護的成員。在Java程序中,很多時候會把**static**成員設置成**private**的,在Scala中需要這樣實現此特性:

      ```scala class X {?? import X._?? def blah = foo } object X {?? private

      def foo = 42 } ```? ## 函數

      在Scala中,函數是一等公民。函數可以像類型一樣被賦值給一個變量,也可以做為一個函數的參數被傳入,甚至還可以做為函數的返回值返回。

      從Java 8開始,Java也具備了部分函數式編程特性。其Lamdba函數允許將一個函數做值賦給變量、做為方法參數、做為函數返回值。

      在Scala中,使用`def`關鍵ygnk來定義一個函數方法:? ```scala scala> def calc(n1: Int,

      n2: Int): (Int, Int) = {????? |?? (n1 + n2, n1 * n2)????? | } calc: (n1:

      Int, n2: Int)(Int, Int)? scala> val (add, sub) = calc(5, 1) add: Int

      = 6 sub: Int = 5 ```

      這里定義了一個函數:`calc`,它有兩個參數:`n1`和`n2`,其類型為:`Int`。`cala`函數的返回值類型是一個有兩個元素的元組,在Scala中可以簡寫為:`(Int,

      Int)`。在Scala中,代碼段的最后一句將做為函數返回值,所以這里不需要顯示的寫`return`關鍵字。? 而`val (add, sub)

      = calc(5,

      1)`一句,是Scala中的抽取功能。它直接把`calc`函數返回的一個`Tuple2`值賦給了`add`他`sub`兩個變量。

      函數可以賦給變量:? ```scala scala> val calcVar = calc _ calcVar: (Int, Int)

      => (Int, Int) =?? scala> calcVar(2, 3) res4: (Int, Int) = (5,6)

      scala> val sum: (Int, Int) => Int = (x, y) => x + y sum: (Int,

      Int) => Int =?? scala> sum(5, 7) res5: Int = 12 ```

      在Scala中,有兩種定義函數的方式:? 1. 將一個現成的函數/方法賦值給一個變量,如:`val calcVar = calc

      _`。下劃線在此處的含意是將函數賦給了變量,函數本身的參數將在變量被調用時再傳入。 2. 直接定義函數并同時賦給變量,如:`val sum:

      (Int, Int) => Int = (x, y) => x + y`,在冒號之后,等號之前部分:`(Int, Int)

      =>

      Int`是函數簽名,代表`sum`這個函數值接收兩個Int類型參數并返回一個Int類型參數。等號之后部分是函數體,在函數函數時,`x`、`y`參數類型及返回值類型在此可以省略。

      **一個函數示例:自動資源管理**? 在我們的日常代碼中,資源回收是一個很常見的操作。在Java 7之前,我們必需寫很多的`try { ...

      } finally { xxx.close() }`這樣的樣版代碼來手動回收資源。Java 7開始,提供了**try with

      close**這樣的自動資源回收功能。Scala并不能使用Java 7新加的**try with

      close**資源自動回收功能,但Scala中有很方便的方式實現類似功能:? ```scala def using[T <:

      AutoCloseable, R](res: T)(func: T => R): R = {?? try {???? func(res)

      } finally {???? if (res != null)?????? res.close()?? } }? val allLine =

      using(Files.newBufferedReader(Paths.get("/etc/hosts"))) {

      reader =>?? @tailrec?? def readAll(buffer: StringBuilder, line:

      String): String = {???? if (line == null) buffer.toString???? else {

      buffer.append(line).append('\n')?????? readAll(buffer,

      reader.readLine())???? }?? }????? readAll(new StringBuilder(),

      reader.readLine()) }? println(allLine) ```

      `using`是我們定義的一個自動化資源管幫助函數,它接愛兩個參數化類型參數,一個是實現了`AutoCloseable`接口的資源類,一個是形如:`T

      =>

      R`的函數值。`func`是由用戶定義的對`res`進行操作的函數代碼體,它將被傳給`using`函數并由`using`代執行。而`res`這個資源將在`using`執行完成返回前調用`finally`代碼塊執行`.close`方法來清理打開的資源。

      這個:`T <:

      AutoCloseable`范型參數限制了**T**類型必需為`AutoCloseable`類型或其子類。`R`范型指定`using`函數的返回值類型將在實際調用時被自動參數化推導出來。我們在**Scala

      Console**中參看`allLine`變量的類型可以看到

      `allLine`將被正確的賦予**String**類型,因為我們傳給`using`函數參數`func`的函數值返回類型就為**String**:

      ```scala scala> :type allLine String ```? 在`readAll`函數的定義處,有兩個特別的地方:

      1. 這個函數定義在了其它函數代碼體內部 2. 它有一個`@tailrec`注解

      在Scala中,因為函數是第一類的,它可以被賦值給一個變量。所以Scala中的`def`定義函數可以等價`val func = (x: Int,

      y: Int) => x +

      y`這個的函數字面量定義函數形式。所以,既然通過變量定義的函數可以放在其它函數代碼體內,通過`def`定義的函數也一樣可以放在其它代碼體內,這和**Javascript**很像。

      `@tailrec`注解的含義是這個函數是尾遞歸函數,編譯器在編譯時將對其優化成相應的**while**循環。若一個函數不是尾遞歸的,加上此注解在編譯時將報錯。

      ## 模式匹配(match case)? 模式匹配是函數式編程里面很強大的一個特性。

      之前已經見識過了模式匹配的簡單使用方式,可以用它替代:**if

      else**、**switch**這樣的分支判斷。除了這些簡單的功能,模式匹配還有一系列強大、易用的特性。? **match

      中的值、變量和類型**? ```scala scala> for {????? |?? x <- Seq(1, false,

      2.7, "one", 'four, new java.util.Date(), new

      RuntimeException("運行時異常"))????? | } {????? |?? val str = x

      match {????? |???? case d: Double => s"double: $d"????? |

      case false => "boolean false"????? |???? case d:

      java.util.Date => s"java.util.Date: $d"????? |???? case 1

      => "int 1"????? |???? case s: String => s"string:

      $s"????? |???? case symbol: Symbol => s"symbol:

      $symbol"????? |???? case unexpected => s"unexpected value:

      $unexpected"????? |?? }????? |?? println(str)????? | } int 1

      boolean false double: 2.7 string: one symbol: 'four java.util.Date: Sun

      Jul 24 16:51:20 CST 2016 unexpected value: java.lang.RuntimeException:

      運行時異常 ```? 上面小試牛刀校驗變量類型的同時完成類型轉換功能。在Java中,你肯定寫過或見過如下的代碼:? ```java public

      模式匹配能很方便的抽取序列的元素,`seqToString`使用了模式匹配以遞歸的方式來將序列轉換成字符串。`case head +:

      tail`將序列抽取成“頭部”和“非頭部剩下”兩部分,`head`將保存序列第一個元素,`tail`保存序列剩下部分。而`case

      Nil`將匹配一個空序列。? **case class的匹配**? ```scala scala> trait Person

      scala> case class Man(name: String, age: Int) extends Person

      scala> case class Woman(name: String, age: Int) extends Person

      scala> case class Boy(name: String, age: Int) extends Person

      scala> val father = Man("父親", 33)? scala> val mather =

      Woman("母親", 30)? scala> val son = Man("兒子", 7)

      scala> val daughter = Woman("女兒", 3)? scala> for (person

      <- Seq[Person](father, mather, son, daughter)) {????? |?? person

      match {????? |???? case Man("父親", age) =>

      println(s"父親今年${age}歲")????? |???? case man: Man if man.age

      < 10 => println(s"man is $man")????? |???? case

      Woman(name, 30) => println(s"${name}今年有30歲")????? |

      case Woman(name, age) => println(s"${name}今年有${age}歲")

      |?? }????? | } 父親今年33歲 母親今年有30歲 man is Man(兒子,7) 女兒今年有3歲 ```

      在模式匹配中對`case

      class`進行**解構**操作,可以直接提取出感興趣的字段并賦給變量。同時,模式匹配中還可以使用**guard**語句,給匹配判斷添加一個`if`表達式做條件判斷。

      ## 并發? Scala是對多核和并發編程的支付做得非常好,它的Future類型提供了執行異步操作的高級封裝。

      Future對象完成構建工作以后,控制權便會立刻返還給調用者,這時結果還不可以立刻可用。Future實例是一個句柄,它指向最終可用的結果值。不論操作成功與否,在future操作執行完成前,代碼都可以繼續執行而不被阻塞。Scala提供了多種方法用于處理future。

      上面代碼創建了10個`Future`對象,`Future.apply`方法有兩個參數列表。第一個參數列表包含一個需要并發執行的命名方法體(by-name

      body);而第二個參數列表包含了隱式的`ExecutionContext`對象,可以簡單的把它看作一個線程池對象,它決定了這個任務將在哪個異步(線程)執行器中執行。`futures`對象的類型為`IndexedSeq[Future[String]]`。本示例中使用`Future.reduce`把一個`futures`的`IndexedSeq[Future[String]]`類型壓縮成單獨的`Future[String]`類型對象。`Await.result`用來阻塞代碼并獲取結果,輸入的`Duration.Inf`用于設置超時時間,這里是無限制。

      這里可以看到,在`Future`代碼內部的`println`語句打印輸出是無序的,但最終獲取的`result`結果卻是有序的。這是因為雖然每個`Future`都是在線程中無序執行,但`Future.reduce`方法將按傳入的序列順序合并結果。

      除了使用`Await.result`阻塞代碼獲取結果,我們還可以使用事件回調的方式異步獲取結果。`Future`對象提供了幾個方法通過回調將執行的結果返還給調用者,常用的有:

      1. onComplete: PartialFunction[Try[T], Unit]:當任務執行完成后調用,無論成功還是失敗 2.

      onSuccess: PartialFunction[T, Unit]:當任務成功執行完成后調用 3. onFailure:

      PartialFunction[Throwable, Unit]:當任務執行失敗(異常)時調用? ```scala import

      scala.concurrent.Future import scala.util.{Failure, Success} import

      scala.concurrent.ExecutionContext.Implicits.global? val futures = (1 to

      2) map {?? case 1 => Future.successful("1是奇數")?? case 2

      => Future.failed(new RuntimeException("2不是奇數")) }

      futures.foreach(_.onComplete {?? case Success(i) => println(i)?? case

      Failure(t) => println(t) })? Thread.sleep(2000) ```

      `futures.onComplete`方法是一個偏函數,它的參數是:`Try[String]`。`Try`有兩個子類,成功是返回`Success[String]`,失敗時返回`Failure[Throwable]`,可以通過模式匹配的方式獲取這個結果。

      ## 總結

      本篇文章簡單的介紹了Scala的語言特性,本文并不只限于Java程序員,任何有編程經驗的程序員都可以看。現在你應該對Scala有了一個基礎的認識,并可以寫一些簡單的代碼了。我在博客中分享了一些《Scala實戰(系列)》文章,介紹更**函數式**的寫法及與實際工程中結合的例子。也歡迎對Scala感興趣的同學與我聯系經,一起交流、學習。

      本文轉載自異步社區

      軟件開發

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:Excel如何禁止重復數據輸入
      下一篇:2019年的WPS置頂怎么換顏色 為什么黑色的(2019年wps表格中的底紋顏色怎樣設置
      相關文章
      gogo全球高清大胆亚洲| 亚洲精品无码日韩国产不卡av| 中文字幕亚洲精品无码| 亚洲日本人成中文字幕| 国产精品亚洲片在线| 国产a v无码专区亚洲av| 一级毛片直播亚洲| 一区国严二区亚洲三区| 国产成人亚洲午夜电影| yy6080久久亚洲精品| 亚洲成a人片在线播放| 国产亚洲综合视频| 亚洲国产精品不卡毛片a在线| 另类专区另类专区亚洲| 亚洲第一区精品日韩在线播放| 亚洲精品日韩一区二区小说| 亚洲欧美熟妇综合久久久久| 亚洲精品无码av中文字幕| 亚洲综合无码一区二区痴汉| 亚洲精品天堂在线观看| 亚洲中文无码卡通动漫野外| 亚洲色大成网站www永久网站| 亚洲色偷偷色噜噜狠狠99| 亚洲国产欧美国产综合一区 | 亚洲高清中文字幕免费| 中文字幕乱码亚洲精品一区| 亚洲一区AV无码少妇电影| 亚洲精华液一二三产区| 国产亚洲美女精品久久久久| 亚洲 另类 无码 在线| 亚洲午夜福利精品久久 | 亚洲人成国产精品无码| 国产性爱在线观看亚洲黄色一级片| 亚洲中文字幕无码专区| 亚洲女同成av人片在线观看| 国产∨亚洲V天堂无码久久久| 久久精品国产亚洲AV麻豆~| 午夜亚洲www湿好大| 亚洲国产精品专区| 亚洲精品GV天堂无码男同| 亚洲精品国产自在久久|