定制软件开发Scala高级语法入门 (六)Scala中的异常&隐式转换&泛型

🙆‍♂️🙆‍♂️ 写在前面

​🏠​ 个人主页:
📚 推荐专栏:定制软件开发更多专栏尽在主页!


​📖​ 本期文章:定制软件开发高级语法入门 (六)Scala中的异常&隐式转换&泛型
定制软件开发本篇文章作为Scala定制软件开发系列的完结篇,定制软件开发感谢各位码友一直以来定制软件开发的支持与厚爱💜


📌本文目录


一、Scala异常

Scala定制软件开发异常语法处理上和Java类似,定制软件开发但是又不尽相同。

1.1、Java中的异常

try {    int a = 10;    int b = 0;    int c = a / b;} catch (ArithmeticException e){    // catch时,定制软件开发需要将范围小的写到前面    e.printStackTrace();} catch (Exception e){    e.printStackTrace();} finally {    System.out.println("finally");}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

java定制软件开发中异常的捕获是从小大大

(1)Java 语言按照 try—catch—finally 定制软件开发的方式来处理异常

(2)定制软件开发不管有没有异常捕获,都会执行 finally,定制软件开发因此通常可以在 finally 定制软件开发代码块中释放资源

(3)定制软件开发可以有多个 catch,定制软件开发分别捕获对应的异常,定制软件开发这时需要把范围小的异定制软件开发常类写在前面, 定制软件开发把范围大的异常类写在后面,否则编译错误。

但是异常并不是我们看上去那么简单

我们来看看下面的代码执行情况是什么?你知道吗?

public class JavaTestException {    public static void main(String[] args) {        int j = test();        System.out.println(j);    }    public static int test(){        int i = 0;        try {            return i++;        }finally {            return ++i;        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

❓ 执行结果为2 这是为什么?

一旦源码看不懂 我们就去看字节码

javap -v JavaTestException 查看字节码文件

1、return关键字不会马上返回结果

2、所有的return返回的都是同一个值:临时变量

所以上述代码中return不会马上返回 它要等finally执行完毕后返回,但是finally里面也有return 就相当于对临时变量进行了操作 最终return返回的都是同一个值。

如果finally里面没有return 那么 临时变量不会被修改 返回 0

1.2、Scala中的

Scala中的异常不区分所谓的编译时异常和运行时异常,也无需显示抛出方法异常,所以Scala中没有throws关键字。

object Scala_exception1 {  def main(args: Array[String]): Unit = {    try {      var n= 10 / 0    } catch {      case ex: ArithmeticException=>{        // 发生算术异常        println("发生算术异常")      }      case ex: Exception=>{        // 对异常处理        println("发生了异常1")      }    } finally {      println("finally")    }  }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

Scala中也要求异常范围大的写在后面

1、我们将可疑代码封装在 try 块中。在 try 块之后使用了一个 catch 处理程序来捕获异常。
如果发生任何异常,catch 处理程序将处理它,程序将不会异常终止。
2、Scala 的异常的工作机制和 Java 一样,但是 Scala 没有“checked(编译期)”异常,
即 Scala 没有编译异常这个概念,异常都是在运行的时候捕获处理。
3、异常捕捉的机制与其他语言中一样,如果有异常发生,catch 子句是按次序捕捉的。
因此,在 catch 子句中,越具体的异常越要靠前,越普遍的异常越靠后,如果把越普遍的异常写在前,
把具体的异常写在后,在 Scala 中也不会报错,但这样是非常不好的编程风格。
4、finally 子句用于执行不管是正常处理还是有异常发生时都需要执行的步骤,一般用于对象的清理工作,这点和 Java 一样。

java 提供了 throws 关键字来声明异常。可以使用方法定义声明异常。它向调用者函数提供了此方法可能引发此异常的信息。它有助于调用函数处理并将该代码包含在 try-catch 块中,以避免程序异常终止。

在 Scala 中,可以使用 throws 注解来声明异常

def main(args: Array[String]): Unit = { f11()}@throws(classOf[NumberFormatException])def f11()={ "abc".toInt}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

二、隐式转换

2.1、什么是隐式转换

在之前的类型学习中,我们已经学习了自动,精度小的类型可以自动转换为精度大的类型,这个转换过程无需开发人员参与,由编译器自动完成,这个转换操作我们称之为隐式转换。

在其他的场合,隐式转换也起到了非常重要的作用。如Scala在程序编译错误时,可以通过隐式转换中类型转换机制尝试进行二次编译,将本身错误无法编译通过的代码通过类型转换后编译通过。慢慢地,这也形成了一种扩展功能的转换机制。

所谓的隐式转换其实就是类型的转换

2.2、隐式函数

在函数前面加上implicit关键字就是隐式函数了

看看下面的代码:

object Scala_Transform1 {  def main(args: Array[String]): Unit = {        // 获取第三方的提供的数据    val age:Int = thirdPart()    println(age)  }  // 第三方 提供的数据 年龄  def thirdPart(): Int = {    20  }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

打印输出20没问题,那么问题来了。第三方发现年龄有半岁,使用int表示不再合适,所以改为了Double类型

// 第三方 提供的数据 年龄def thirdPart(): Double = {  20.30}
  • 1
  • 2
  • 3
  • 4

之前我们提到过OCP开发原则,在不改变源码的情况下如何使得编译器不报错

这里我们就提到了Scala中的隐式转换机制,他会在全局寻找可以使得编译通过的方法,使得二次编译通过

所以这里我们编写一个方法 使得double类型数据转换为int类型数据

// 增加一个将double类型转为int类型的方法 def transform(num:Double): Int ={  num.toInt}
  • 1
  • 2
  • 3
  • 4

但是这个方法和我们的隐式转换机制怎么联系起来呢?加上implicit关键字

 // 增加一个将double类型转为int类型的方法implicit def transform(num:Double): Int ={   num.toInt }
  • 1
  • 2
  • 3
  • 4

隐式转换可以在不需改任何代码的情况下,扩展某个类的功能。

2.2、隐式参数

普通方法或者函数中的参数可以通过 implicit 关键字声明为隐式参数,调用该方法时, 就可以传入该参数,编译器会在相应的作用域寻找符合条件的隐式值。

(1)同一个作用域中,相同类型的隐式值只能有一个

(2)编译器按照隐式参数的类型去寻找对应类型的隐式值,与隐式值的名称无关。

(3)隐式参数优先于默认参数

object Scala_Transform2 {  def main(args: Array[String]): Unit = {    // TODO 隐式转换 隐式参数    // 隐式参数    def reg(implicit passwd:String = "000000"): Unit ={      println(s"密码为:${passwd}")    }    reg()    reg("123123")    // 隐式变量    implicit val passwd = "123456"  // 通过隐式参数可以修改默认值    // 隐式参数是不用传递的,这个过程是由编译器完成    reg  // 输出的默认密码就是123456    // 如果传了参数 那么就不去查找隐式变量了    reg()  // 输出 000000  }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

在同一个作用域中相同的转换规则会报错

2.3、隐式类

在 Scala2.10 后提供了隐式类,可以使用 implicit 声明类,隐式类的非常强大,同样可以扩展类的功能,在集合中隐式类会发挥重要的作用

object Scala_Transform3 {  def main(args: Array[String]): Unit = {    // TODO 隐式转换 隐式参数        val user = new User()    user.insertUser()      }      class User{    def insertUser(): Unit ={      println("添加用户!")    }  }  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

加入我们想要扩展一个修改用户的功能该怎么做?

我们可以再写一个类扩展功能

class UserExtend(){  def updateUser(): Unit = {    println("修改用于!")  }}
  • 1
  • 2
  • 3
  • 4
  • 5

然后在再写一个隐式函数做转换

implicit def transforUser(user: User): UserExtend = {  new UserExtend}
  • 1
  • 2
  • 3

但是这样做显得十分的麻烦

我们可以使用隐式类

implicit class UserExtend(user: User) {  def updateUser(): Unit = {    println("修改用于!")  }}
  • 1
  • 2
  • 3
  • 4
  • 5

这样更容易扩展类的功能

注意事项

1、其所带的构造参数有且只能有一个

2、隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是顶级的。

2.4、隐式机制

所谓的隐式机制,就是一旦出现编译错误时,编译器会从哪些地方查找对应的隐式转换规则

1、当前代码作用域

2、当前代码上级作用域

3、当前类所在的包对象

4、当前类(对象)的父类(父类)或特质(父特质)

其实最直接的方式就是直接导入。

三、

3.1、简介

Scala的泛型和Java中的泛型表达的含义都是一样的,对处理的数据类型进行约束,但是Scala提供了更加强大的功能

1、泛型和类型的区别?

​ 类型是约束外部的数据
泛型是约束内部的数据

2、泛型在某些场合中其实就是类型参数,用于向类中传递采纳数

3、泛型只在编译时有效,将这个操作称之为 “泛型擦除”

4、泛型的主要目的是为了约束内部数据

scala中的泛型用[] 表示

3.2、泛型转换

3.2.1、泛型不可变

scala中的泛型也是不可变得

new 的是类型 而不是泛型 泛型只是约束力内部的数据

def main(args: Array[String]): Unit = {        val test1 : Test[User] = new Test[User] // OK        val test2 : Test[User] = new Test[Parent] // Error        val test3 : Test[User] = new Test[SubUser]  // Error    }    class Test[T] {    }    class Parent {    }    class User extends Parent{    }    class SubUser extends User {    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

3.2.2、泛型协变

马丁想着泛型和类型不是同一个层面的东西,所以无法联合使用,不方便,如果能将类型和泛型当成一个整体来使用的话不就方便了?

如果将类型和泛型联合使用,那么类型相同,泛型存在父子关系,那么整体就存在父子关系,这种操作其实就是一种变化,称之为 协变 +T

def main(args: Array[String]): Unit = {        val test1 : Test[User] = new Test[User] // OK        val test2 : Test[User] = new Test[Parent] // Error        val test3 : Test[User] = new Test[SubUser]  // OK    }    class Test[+T] {    }    class Parent {    }    class User extends Parent{    }    class SubUser extends User {    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

3.2.3、泛型逆变

如果将类型和泛型联合使用,那么类型相同,泛型存在父子关系,那么整体就存在子父关系,这种操作其实就是一种变化,称之为逆 变 -T

 def main(args: Array[String]): Unit = {        val test1 : Test[User] = new Test[User] // OK        val test2 : Test[User] = new Test[Parent] // OK        val test3 : Test[User] = new Test[SubUser]  // Error    }    class Test[-T] {    }    class Parent {    }    class User extends Parent{    }    class SubUser extends User {    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

3.2.4、泛型的上限

object Scala_geniric4 {  // 泛型的上限  def main(args: Array[String]): Unit = {    val parent: Parent = new Parent()    val user: User = new User()    val subuser: SubUser = new SubUser()//    test[Parent](parent) // Error    test[User](user) // OK    test[SubUser](subuser) // OK  }  // 上限采用颜文字   def test[A <: User](a: A): Unit = {    println(a)  }  class Parent {  }  class User extends Parent {  }  class SubUser extends User {  }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

3.2.5、泛型的下限

def main(args: Array[String]): Unit = {        val parent : Parent = new Parent()        val user : User = new User()        val subuser : SubUser = new SubUser()        test[Parent](parent) // OK        test[User](user)   // OK        test[SubUser](subuser) // Error    }    def  test[A>:User]( a : A ): Unit = {        println(a)    }    class Parent {    }    class User extends Parent{    }    class SubUser extends User {    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

3.2.6、上下文限定

1)语法

def f[A : B](a: A) = println(a) //等同于def f[A](a:A)(implicit arg:B[A])=println(a)

2)说明

上下文限定是将泛型和隐式转换的结合产物,以下两者功能相同,使用上下文限定[A : Ordering]之后,方法内无法使用隐式参数名调用隐式参数,需要通过 implicitly[Ordering[A]] 获取隐式变量,如果此时无法查找到对应类型的隐式变量,会发生出错误。

object ScalaGeneric {    def main(args: Array[String]): Unit = {        def f[A : Test](a: A) = println(a)        implicit val test : Test[User] = new Test[User]        f( new User() )    }    class Test[T] {    }    class Parent {    }    class User extends Parent{    }    class SubUser extends User {    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发