十二、異常處理
異常
- Scala 的異常處理和其它語言比如 Java 類似。
- Scala 的方法可以通過拋出異常的方法的方式來終止相關代碼的運行,不必通過返回值。
package exception
import java.io.IOException
/**
* scala異常分類和java一樣的
* Throwable
* |- Error
* |- Exception
* |- 未檢查異常
* |- 已檢查異常
*
* 異常處理的方式:
* - 消極處理: throw 異常類 沒有throws
* - 積極處理: try{...}catch(){...}finally{...}
*/
object ExceptionDemo {
def main(args: Array[String]): Unit = {
try {
println("start")
// throw new RuntimeException("程序終止!!") // Exception in thread "main" java.lang.RuntimeException: 程序終止!!
throw new IOException
println("end")
} catch {
// 模式匹配
case e1: RuntimeException => println("runtime exception")
case e2: Exception => println("exception")
case _ => println("xxxx") // 如果以上聲明的兩種異常不匹配,則進入最後一個
} finally {
println("釋放資源")
}
}
}
十三、隱式轉換
隱式轉換函數(implicit conversion function)指的是以implicit關鍵字聲明的帶有單個參數的函數。這樣的函數將被自動應用,將值從一種類型轉換爲另一種類型。隱式轉換函數叫什麼名字是無所謂的,因爲通常不會由用戶手動調用,而是由Scala進行調用。但是如果要使用隱式轉換,則需要對隱式轉換函數進行導入(import
)。因此通常建議將隱式轉換函數的名稱命名爲“one2one”的形式。
常用使用方式:
- 隱式值
- 隱式參數
- 參數的隱式轉換
- 隱式類
Scala會考慮如下位置的隱式轉換函數:
- 位於源或目標類型的伴生對象中的隱式函數
- 位於當前作用域可以以單個標識符指代的隱式函數
隱式轉換在如下三種不同情況下會被考慮:
- 當表達式類型與預期類型不同時
- 當對象訪問一個不存在成員時
- 當對象調用某個方法,而這個方法的參數聲明與傳入參數不匹配時
有三種情況編譯器不會嘗試使用隱式轉換
- 如果代碼能夠在不使用隱式轉換的前提下通過編譯,則不會使用隱式轉換
- 編譯器不會嘗試同時執行多個轉換
- 存在二義性的轉換是錯誤
隱式值
/**
* implicit 隱式值
*/
object ImplicitValue {
// 隱式值聲明 對象內部或者作用域
implicit val name: String = "Hello"
// implicit val address:String = "bj" // error
implicit val sex: Boolean = false // ok
def main(args: Array[String]): Unit = {
// 使用隱式值
val newValue = implicitly[String]
val newValue2 = implicitly[Boolean]
println(newValue)
println(newValue2)
}
}
隱式參數(傳值)
方法或者函數的參數,在聲明時有implicit。要求參數之中只能有一個implicit類型匹配。
package implicits
/**
* 隱式參數
*
*/
object ImplicitParams {
// 聲明隱式值 缺省值
implicit var num: Int = 10
def main(args: Array[String]): Unit = {
println(sum(10))
println(sum(10)(20))
}
def sum(x: Int)(implicit y: Int): Int = { // y是隱式參數 適用於柯里化函數
x + y
}
// def sum2(x: Int,implicit y: Int): Int = { // 不可以 普通函數是無法使用隱式參數
// x + y
// }
implicit val str: String = "Hello"
// def sum3(x: Int)(implicit y: Int)(implicit z: String): Int = { // 不可以 隱式參數只能在柯里化函數中出現一次
//
// }
}
參數隱式轉換
class Student(var name: String)
object Implicit1 {
def main(args: Array[String]): Unit = {
sayHi("zs") // 傳入的類型和方法的參數類型 不匹配,觸發隱式轉換 str--->student
}
implicit def strToStudent(str: String): Student = {
new Student(str)
}
def sayHi(student: Student): Unit = {
println("Hello:" + student.name)
}
}
隱式轉換增強現有類型
object Implicit2 {
implicit def manToSuperMan(man: Man): SuperMan = new SuperMan(man.name)
def main(args: Array[String]): Unit = {
val man = new Man("小張")
man.fly()
}
}
class Man(val name: String)
class SuperMan(val name: String) {
def fly(): Unit = {
println("超人會飛...")
}
}
隱式類
在上面的例子中爲了讓人也能夠飛,需要在SuperMan中定義fly方法,再寫一個隱式轉換函數,將Man隱式轉換爲SuperMan。這種寫法過於囉嗦,可以使用隱式類實現等價功能
class Man2(val name: String)
object Implicit5 {
def main(args: Array[String]): Unit = {
implicit class SuperMan2(man: Man2) {
var name: String = _
def fly = {
this.name = man.name
println(s"$name ---> 超人會飛")
}
}
val man = new Man2("zs")
man.fly
}
}
隱式類就是在類定義前加一個implicit
關鍵字,這表示它的構造函數是一個隱式轉換函數,能夠將參數的類型轉換成自己的類型,在這裏就是構造函數SuperMan2(man: Man2)
定義了Man2
到SuperMan2
的隱式轉換。
注意:使用隱式類時需要注意以下限制條件
- 只能在別的trait/類/對象內部定義
- 構造函數只能攜帶一個非隱式參數
- implict關鍵字不能用於case類
引入隱式轉換
隱式值
- 定義在伴生對象或者作用域
- 引用其它對象的
import 對象._
package implicits
object Implicit3 {
// 伴生類的類體
implicit var x: Int = 0
def main(args: Array[String]): Unit = {
// 伴生類的函數體
implicit var str: String = "Hi"
import AA._ // 類似於java的靜態導入
var ll: Long = implicitly[Long]
println(ll)
}
}
object AA {
// 其它對象中定義了一個隱式值
implicit var l: Long = 1000L
}
隱式參數
- 定義在伴生對象或者作用域或
import
package implicits
object Implicit4 {
def main(args: Array[String]): Unit = {
implicit var x: Int = 10
// def sum(x: Int)(implicit y: Int): Int = {
// x + y
// }
import BB._
println(sum(10))
}
// 類體
// def sum(x: Int)(implicit y: Int): Int = {
// x + y
// }
}
object BB {
def sum(x: Int)(implicit y: Int): Int = {
x + y
}
}
參數隱式轉換
- 定義在伴生對象或者作用域
- 其它類,需要
import
package implicits
import CC._
object Implicit5 {
def main(args: Array[String]): Unit = {
sayHi("ls")
// implicit def str2Student(str: String): Student2 = {
// new Student2(str)
// }
}
def sayHi(student: Student2): Unit = {
println(student.name)
}
// implicit def str2Student(str: String): Student2 = {
// new Student2(str)
// }
}
class Student2(var name: String)
object CC {
implicit def str2Student(str: String): Student2 = {
new Student2(str)
}
}
隱式類
package implicits
import DD._
/**
*
* 隱式類
*/
object Implicit2 {
def main(args: Array[String]): Unit = {
val man2 = new Man2("zs")
man2.fly
println(man2.name)
// 隱式類 接受Man2對象 構建SuperMan2獨享
// implicit class SuperMan2(man2: Man2) {
// var name: String = _
//
// def fly = {
// // this.name = man2.name
// println("飛翔...")
// }
// }
}
}
class Man2(var name: String)
//implicit class SuperMan2(man2: Man2) { //error
// var name: String = _
//
// def fly = {
// // this.name = man2.name
// println("飛翔...")
// }
//}
object DD {
implicit class SuperMan2(man2: Man2) { //error
var name: String = _
def fly = {
// this.name = man2.name
println("飛翔...")
}
}
}