scala异常、隐式转换、泛型使用详解

1、异常

  1. 我们将可疑代码封装在try块中。在try块之后使用了一个catch处理程序来捕获异常。如果发生任何异常,catch处理程序将处理它,程序将不会异常终止。
  2. Scala的异常的工作机制和Java一样,但是Scala没有“checked(编译期)”异常,即Scala没有编译异常这个概念,异常都是在运行的时候捕获处理。
  3. 异常捕捉的机制与其他语言中一样,如果有异常发生,catch子句是按次序捕捉的。因此,在catch子句中,越具体的异常越要靠前,越普遍的异常越靠后,如果把越普遍的异常写在前,把具体的异常写在后,在Scala中也不会报错,但这样是非常不好的编程风格。
  4. finally子句用于执行不管是正常处理还是有异常发生时都需要执行的步骤,一般用于对象的清理工作,这点和Java一样。
  5. 用throw关键字,抛出一个异常对象。所有异常都是Throwable的子类型。throw表达式是有类型的,就是Nothing,因为Nothing是所有类型的子类型,所以throw表达式可以用在需要类型的地方
  6. 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、隐式转换

  1. 隐式值、隐式参数
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
  }
}
  1. 隐式函数练习运用流获取本地文件的行数
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、泛型

  1. 协变和逆变
  • 协变: 如果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)

猜你喜欢

转载自blog.csdn.net/weixin_46122692/article/details/109017168
今日推荐