1、异常
- 我们将可疑代码封装在try块中。在try块之后使用了一个catch处理程序来捕获异常。如果发生任何异常,catch处理程序将处理它,程序将不会异常终止。
- Scala的异常的工作机制和Java一样,但是Scala没有“checked(编译期)”异常,即Scala没有编译异常这个概念,异常都是在运行的时候捕获处理。
- 异常捕捉的机制与其他语言中一样,如果有异常发生,catch子句是按次序捕捉的。因此,在catch子句中,越具体的异常越要靠前,越普遍的异常越靠后,如果把越普遍的异常写在前,把具体的异常写在后,在Scala中也不会报错,但这样是非常不好的编程风格。
- finally子句用于执行不管是正常处理还是有异常发生时都需要执行的步骤,一般用于对象的清理工作,这点和Java一样。
- 用throw关键字,抛出一个异常对象。所有异常都是Throwable的子类型。throw表达式是有类型的,就是Nothing,因为Nothing是所有类型的子类型,所以throw表达式可以用在需要类型的地方
- Scala提供了throws关键字来声明异常。可以使用方法定义声明异常。它向调用者函数提供了此方法可能引发此异常的信息。它有助于调用函数处理并将该代码包含在try-catch块中,以避免程序异常终止。在Scala中,可以使用throws注释来声明异常
import java.io.FileNotFoundException
import scala.io.Source
object Demo03Exception {
def main(args: Array[String]): Unit = {
/*
异常处理
*/
try {
val source = Source.fromFile("a.txt")
} catch {
/* 偏函数 */
case e:FileNotFoundException => println(e)
case e:NullPointerException => println(e)
case e:IndexOutOfBoundsException => println(e)
case e:ClassCastException => println(e)
case e:ClassNotFoundException => println(e)
}finally {
println("无论程序是否有异常,都会被执行!!!")
}
}
}
2、隐式转换
- 隐式值、隐式参数
object Implicit{
/* 设置隐式值 关键字implicit */
implicit val name = "zhangsan"
implicit val age = 18
implicit var addr = "八达岭!!!"
}
object Demo04Implicit {
def main(args: Array[String]): Unit = {
/*
隐式转换
隐式转换可以在不需改任何代码的情况下,扩展某个类的功能
*/
/*
隐式参数
普通方法或者函数可以通过 implicit关键字声明隐式参数,调用该方法时,就可以传入该参数,
编译器会在相应的作用域寻找符合条件的隐式值
说明
同一个作用域中,相同类型的隐式值只能有一个
编译器按照隐式参数的类型去寻找对应类型的隐式值,与隐式值的名称无关。
隐式参数优先于默认参数
*/
def getInfo(implicit name: String,age: Int) = {
println(s"$name $age")
}
/* 正常调用 */
getInfo("wangwu",22)
/* 导入隐式值 */
import Implicit.name
import Implicit.age
/* 也可以这样 import Implicit._ */
/* 在可见区域向上查找,并且同种类型只能有一个隐士的,隐式调用 */
getInfo
}
}
- 隐式函数练习运用流获取本地文件的行数
import java.io.{
BufferedReader, File, FileReader}
object Demo05ImpliciMethod {
/* 定义一个隐式函数,将File类型转换成RichFile类型 */
implicit def fileToRichFile(file: File) = {
new RichFile(file)
}
def main(args: Array[String]): Unit = {
/*
隐式函数练习,运用流获取本地文件的行数
*/
val file = new File("E:/快捷键.txt")
/*
借用隐式方法 直接用 File对象调用自定义类RichFile的linesCount()方法
但是隐式方法的参数类型必须是File 也就是 隐式方法的参数类型和 调用对象的类型必须一致,才能使用隐式方法 隐式转换
*/
val linesCount = file.linesCount()
println(s"file文件里的行数是: $linesCount 行")
}
}
/* 自定义一个RichFile类,封装File类 */
class RichFile(file: File) {
/* 定义方法返回文件的记录行数 */
def linesCount(): Int = {
val fileReader = new FileReader(file)
val bufferReader = new BufferedReader(fileReader)
/* 总行数初始为0 */
var sum = 0
try {
/* 一次读取一行 */
var line = bufferReader.readLine()
while (line != null) {
/* 行数加1 */
sum += 1
line = bufferReader.readLine()
}
} catch {
case _: Exception => sum
} finally {
/* 关流 */
fileReader.close()
bufferReader.close()
}
/* 返回总行数 */
sum
}
}
3、泛型
- 协变和逆变
- 协变: 如果B是A的子类,Demo1[B] 也是 Demo1[A]的子类,称为协变,相当于java的向上转型(父类引用指向子类对象)
- 逆变: 如果B是A的子类,Demo1[A] 也是 Demo1[B]的子类,称为逆变,相当于java的向下转型(强转)
object Demo06 {
def main(args: Array[String]): Unit = {
/*
泛型
协变 逆变
*/
val animal = new Animal
val bird = new Bird
val value1: Demo1[Animal] = new Demo1[Animal](animal)
val value2: Demo1[Bird] = new Demo1[Bird](bird)
/* 类似java的向上转型 父类引用指向子类对象 scala是协变 */
val value3: Demo1[Animal] = value2
//val value4: Demo1[Bird] = value1
val value5: Demo2[Animal] = new Demo2[Animal](animal)
val value6: Demo2[Bird] = new Demo2[Bird](bird)
/* 类似java的向下转型 通过引用类型强转 scala是逆变 */
val value7: Demo2[Bird] = value5
}
}
class Animal
class Bird extends Animal
//协变: 如果B是A的子类,Demo1[B] 也是 Demo1[A]的子类,称为协变
class Demo1[+T](obj:T)
//逆变: 如果B是A的子类,Demo1[A] 也是 Demo1[B]的子类,称为逆变
class Demo2[-T](obj:T)
2.泛型上下限、上下文限定
object Demo07Bounds {
def main(args: Array[String]): Unit = {
/*
泛型
泛型上限 泛型下限
泛型的上下限的作用是对传入的泛型进行限定
上下文限定
上下文限定是将泛型和隐式转换的结合产物,
以下两者功能相同,使用上下文限定[A : Ordering]之后,
方法内无法使用隐式参数名调用隐式参数,需要通过implicitly[Ordering[A]]获取隐式变量。
*/
val grandFather = new GrandFather
val father = new Father("关羽")
val child = new Child("关平")
getObj01[Father](father)
getObj01[Child](child)
// getObj01[GrandFather](grandFather)
getObj02[Father](father)
// getObj02[Child](child)
getObj02[GrandFather](grandFather)
}
/* 上边界: <: 只能传入本类和子类 */
def getObj01[T <: Father](obj: T) = {
/* 类型检查 */
if (obj.getClass == classOf[Father]){
/* 类型转换 */
val father = obj.asInstanceOf[Father]
println(father.name)
}else if (obj.getClass == classOf[Child]){
val child = obj.asInstanceOf[Child]
println(child.name)
}
}
/* 下边界: >: 只能传入本类和父类 */
def getObj02[T >: Father](obj: T) = {
/* 类型检查 */
if (obj.getClass == classOf[Father]){
/* 类型转换 */
val father = obj.asInstanceOf[Father]
println(father.name)
}else if (obj.getClass == classOf[GrandFather]){
val grandFather = obj.asInstanceOf[GrandFather]
println("grandFather")
}
}
/* 上下文限定 */
def func01[A: Ordering](a:A,b:A) = {
/* 方法内无法使用隐式参数名调用隐式参数,需要通过implicitly[Ordering[A]]获取隐式变量 */
implicitly[Ordering[A]].compare(a,b)
}
def func02[A](a:A,b:A)(implicit ord: Ordering[A]) = {
ord.compare(a,b)
}
}
class GrandFather
class Father(var name: String) extends GrandFather
class Child(name: String) extends Father(name)