十二、异常处理
异常
- 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("飞翔...")
}
}
}