val user = User("zhangsan",11),该语句在执行时,实际调用的是 User 伴生对象中的apply 方法,因此不用 new 关键字就能构造出相应的对象。当将 User("zhangsan", 11)写在 case 后时[case User("zhangsan", 11) => "yes"],会默认调用 unapply 方法(对象提取器),user 作为 unapply 方法的参数,unapply 方法将 user 对象的 name 和 age 属性提取出来,与User("zhangsan", 11)中的属性值进行匹配case 中对象的 unapply 方法(提取器)返回 Some,且所有属性均一致,才算匹配成功,属性不一致,或返回 None,则匹配失败。若只提取对象的一个属性,则提取器为 unapply(obj:Obj):Option[T]若提取对象的多个属性,则提取器为 unapply(obj:Obj):Option[(T1,T2,T3…)]若提取对象的可变个属性,则提取器为 unapplySeq(obj:Obj):Option[Seq[T]] 2)样例类语法:case class Person (name: String, age: Int)说明○1 样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中自动提供了一些常用的方法,如 apply、unapply、toString、equals、hashCode 和 copy。○2 样例类是为模式匹配而优化的类,因为其默认提供了 unapply 方法,因此,样例类可以直接使用模式匹配,而无需自己实现 unapply 方法。○3 构造器中的每一个参数都成为 val,除非它被显式地声明为 var(不建议这样做)实操上述匹配对象的案例使用样例类会节省大量代码case class User(name: String, age: Int)object TestMatchUnapply {def main(args: Array[String]): Unit = { val user: User = User("zhangsan", 11) val result = user match {case User("zhangsan", 11) => "yes" case _ => "no"}println(result)}}变量声明中的模式匹配case class Person(name: String, age: Int)object TestMatchVariable {def main(args: Array[String]): Unit = {val (x, y) = (1, 2) println(s"x=$x,y=$y")val Array(first, second, _*) = Array(1, 7, 2, 9) println(s"first=$first,second=$second")val Person(name, age) = Person1("zhangsan", 16) println(s"name=$name,age=$age")}}for 表达式中的模式匹配object TestMatchFor {def main(args: Array[String]): Unit = {val map = Map("A" -> 1, "B" -> 0, "C" -> 3)for ((k, v) <- map) { //直接将 map 中的 k-v 遍历出来println(k + " -> " + v) //3 个}println("")//遍历 value=0 的 k-v ,如果 v 不是 0,过滤for ((k, 0) <- map) {println(k + " --> " + 0) // B->0}println("")//if v == 0 是一个过滤的条件for ((k, v) <- map if v >= 1) {println(k + " ---> " + v) // A->1 和 c->33}}}偏函数中的模式匹配(了解)偏函数也是函数的一种,通过偏函数我们可以方便的对输入参数做更精确的检查。例如该偏函数的输入类型为List[Int],而我们需要的是第一个元素是 0 的集合,这就是通过模式匹配实现的。偏函数定义val second: PartialFunction[List[Int], Option[Int]] = { case x :: y :: _ => Some(y)}注:该偏函数的功能是返回输入的List 集合的第二个元素偏函数原理上述代码会被 scala 编译器翻译成以下代码,与普通函数相比,只是多了一个用于参数检查的函数——isDefinedAt,其返回值类型为 Boolean。偏函数使用偏函数不能像 second(List(1,2,3))这样直接使用,因为这样会直接调用 apply 方法,而应该调用 applyOrElse 方法,如下applyOrElse 方法的逻辑为 if (ifDefinedAt(list)) apply(list) else default。如果输入参数满足条件,即 isDefinedAt 返回 true,则执行 apply 方法,否则执行 defalut 方法,default 方法为参数不满足要求的处理逻辑。案例实操需求将该List(1,2,3,4,5,6,"test")中的 Int 类型的元素加一,并去掉字符串。def main(args: Array[String]): Unit = {val list = List(1,2,3,4,5,6,"test")val list1 = list.map {a =>a match {case i: Int => i + 1case s: String =>s + 1}}println(list1.filter(a=>a.isInstanceOf[Int]))}实操方法一:List(1,2,3,4,5,6,"test").filter(_.isInstanceOf[Int]).map(_.asInstanceOf[Int] + 1).foreach(println)方法二:List(1, 2, 3, 4, 5, 6, "test").collect { case x: Int => x + 1 }.foreach(println)第 9 章 异 常语法处理上和 Java 类似,但是又不尽相同。Java 异常处理public class ExceptionDemo {public static void main(String[] args) { 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");}}}注意事项Java 语言按照 try—catch—finally 的方式来处理异常不管有没有异常捕获,都会执行 finally,因此通常可以在 finally 代码块中释放资源。可以有多个 catch,分别捕获对应的异常,这时需要把范围小的异常类写在前面, 把范围大的异常类写在后面,否则编译错误。Scala 异常处理def main(args: Array[String]): Unit = {try {var n= 10 / 0}catch {case ex: ArithmeticException=>{// 发生算术异常println("发生算术异常")}case ex: Exception=>{// 对异常处理println("发生了异常 1")println("发生了异常 2")}}finally {println("finally")}}我们将可疑代码封装在 try 块中。在 try 块之后使用了一个 catch 处理程序来捕获异常。如果发生任何异常,catch 处理程序将处理它,程序将不会异常终止。Scala 的异常的工作机制和 Java 一样,但是 Scala 没有“checked(编译期)”异常,即 Scala 没有编译异常这个概念,异常都是在运行的时候捕获处理。异常捕捉的机制与其他语言中一样,如果有异常发生,catch 子句是按次序捕捉的。因此,在catch 子句中,越具体的异常越要靠前,越普遍的异常越靠后,如果把越普遍的异常写在前,把具体的异常写在后,在 Scala 中也不会报错,但这样是非常不好的编程风格。finally 子句用于执行不管是正常处理还是有异常发生时都需要执行的步骤,一般用于对象的清理工作,这点和 Java 一样。用 throw 关键字,抛出一个异常对象。所有异常都是Throwable 的子类型。throw 表达式是有类型的,就是 Nothing,因为 Nothing 是所有类型的子类型,所以 throw 表达式可以用在需要类型的地方def test():Nothing = {throw new Exception("不对")}java 提供了 throws 关键字来声明异常。可以使用方法定义声明异常。它向调用者函数提供了此方法可能引发此异常的信息。它有助于调用函数处理并将该代码包含在 try-catch 块中,以避免程序异常终止。在 Scala 中,可以使用 throws 注解来声明异常第 10 章 隐式转换 当编译器第一次编译失败的时候,会在当前的环境中查找能让代码编译通过的方法,用 于将类型进行转换,实现二次编译隐式函数说明隐式转换可以在不需改任何代码的情况下,扩展某个类的功能。案例实操需求:通过隐式转化为 Int 类型增加方法。class MyRichInt(val self: Int) { def myMax(i: Int): Int = {if (self < i) i else self}def myMin(i: Int): Int = { if (self < i) self else i}}object TestImplicitFunction {// 使用 implicit 关键字声明的函数称之为隐式函数implicit def convert(arg: Int): MyRichInt = { new MyRichInt(arg)}def main(args: Array[String]): Unit = {// 当想调用对象功能时,如果编译错误,那么编译器会尝试在当前作用域范围内查找能调用对应功能的转换规则,这个调用过程是由编译器完成的,所以称之为隐式转换。也称之为自动转换println(2.myMax(6))}}隐式参数普通方法或者函数中的参数可以通过 implicit 关键字声明为隐式参数,调用该方法时, 就可以传入该参数,编译器会在相应的作用域寻找符合条件的隐式值。说明同一个作用域中,相同类型的隐式值只能有一个编译器按照隐式参数的类型去寻找对应类型的隐式值,与隐式值的名称无关。隐式参数优先于默认参数案例实操object TestImplicitParameter {implicit val str: String = "hello world!"def hello(implicit arg: String="good bey world!"): Unit = { println(arg)}def main(args: Array[String]): Unit = { hello}}隐式类在 Scala2.10 后提供了隐式类,可以使用 implicit 声明类,隐式类的非常强大,同样可以扩展类的功能,在集合中隐式类会发挥重要的作用。隐式类说明其所带的构造参数有且只能有一个隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是顶级的。案例实操object TestImplicitClass {implicit class MyRichInt(arg: Int) { def myMax(i: Int): Int = {if (arg < i) i else arg}def myMin(i: Int) = {if (arg < i) arg else i}}def main(args: Array[String]): Unit = { println(1.myMax(3))}}隐式解析机制说明首先会在当前代码作用域下查找隐式实体(隐式方法、隐式类、隐式对象)。( 一般是这种情况)如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找。类型的作用域是指与该类型相关联的全部伴生对象以及该类型所在包的包对象。案例实操package com.zpark.chapter10import com.zpark.chapter10.Scala05_Transform4.Teacher//(2)如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找。类型的作用域是指与该类型相关联的全部伴生模块,object TestTransform extends PersonTrait {def main(args: Array[String]): Unit = {//(1)首先会在当前代码作用域下查找隐式实体val teacher = new Teacher() teacher.eat()teacher.say()}class Teacher {def eat(): Unit = { println("eat...")}}}trait PersonTrait {}object PersonTrait {// 隐式类 : 类型 1 => 类型 2implicit class Person5(user:Teacher) {def say(): Unit = { println("say...")}}}第 11 章 泛 型协变和逆变1)语法class MyList[+T]{ //协变}class MyList[-T]{ //逆变}class MyList[T] //不变2)说明协变:Son 是 Father 的子类,则 MyList[Son] 也作为 MyList[Father]的“子类”。逆变:Son 是 Father 的子类,则 MyList[Son]作为 MyList[Father]的“父类”。不变:Son 是 Father 的子类,则 MyList[Father]与 MyList[Son]“无父子关系”。3)实操泛型上下限语法Class PersonList[T <: Person]{ //泛型上限}Class PersonList[T >: Person]{ //泛型下限}说明泛型的上下限的作用是对传入的泛型进行限定。实操上下文限定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]] 获取隐式变量,如果此时无法查找到对应类型的隐式变量,会发生出错误。3)实操第 12 章 总 结开发环境要求掌握必要的 Scala 开发环境搭建技能。变量和数据类型掌握 var 和 val 的区别掌握数值类型(Byte、Short、Int、Long、Float、Double、Char)之间的转换关系流程控制掌握 if-else、for、while 等必要的流程控制结构,掌握如何实现 break、continue 的功能。函数式编程掌握高阶函数、匿名函数、函数柯里化、闭包、函数参数以及函数至简原则。面向对象掌握 Scala 与 Java 继承方面的区别、单例对象(伴生对象)、构造方法、特质的用法及功能。集合掌握常用集合的使用、集合常用的计算函数。模式匹配掌握模式匹配的用法下划线掌握下划线不同场合的不同用法异常掌握异常常用操作即可隐式转换掌握隐式方法、隐式参数、隐式类,以及隐式解析机制泛型掌握泛型语法第 13 章 IDEA 快捷键快速生成程序入口:main 输入 main->回车自动补全变量:.var输入 1.var->回车val i: Int = 2快速打印:.sout输入 1.sout->回车println(1)快速生成 for 循环:遍历对象.for输 入 1 to 3.forfor (elem <- 1 to 3) {}查看当前文件的结构:Ctrl + F12 6) 格式化当前代码:Ctrl + Shift + L7) 自动为当前代码补全变量声明:Ctrl + Shift + V更多请查看截图: