• Scala教程


    1. 基础语法

    Scala语言是基于Java虚拟机运行的,所以基本的语法和Java是没有区别的。但是为了简化Java的开发以及融合其他的编程语言的优点和特性,Scala在基本的语法上做了大量的修改和优化,让程序员开发起来更简单,方便,灵活。

    1.1 变量

    Scala声明变量有两种方式,一个用val,一个用var。

    val / var 变量名 : 变量类型 = 变量值

    val定义的值是不可变的,它不是一个常量,是不可变量,或称之为只读变量

    1.2. 常用类型

    Scala语言是完全面向对象的语言,所以并不区分基本类型和引用类型,这些类型都是对象,我们称之为常用类型。

    Scala常用类型中包含有7种数值类型:Byte、Char、Short、Int、Long、Float、Double及Boolean类型,还有String类型。

    Byte

    8, 有符号

    Char

    16, 无符号

    Short

    16, 有符号

    Int

    32, 有符号

    Long

    64, 有符号

    Double

    64, 双精度浮点数

    Boolean

    true 或者 false

    String

    其实就是由Char数组组成

    2. 控制结构

    scala中的循环表达式分为3类:① to  ②  Range   ③ until  【底层实际上都是scala.collection.immutable.Range】

    • to : 前闭后闭
    • Range : 前闭后开, 可以使用步长,但是步长不能为0
    • until : 前闭后开
    1. println(1 to 10) //Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    2. println(Range(1, 10)) //Range(1, 2, 3, 4, 5, 6, 7, 8, 9)
    3. println(Range(1, 10, 2)) // Range(1, 3, 5, 7, 9)
    4. println(1 until 10) // Range(1, 2, 3, 4, 5, 6, 7, 8, 9)

    2.1  if else表达式

    1. //演示scala条件表达式
    2. object IfScala extends App {
    3. val x = 0
    4. val resBoolean = if (x > 0) true else false //false
    5. // 0 > 0 不成立, 且代码没有 else 分支, res2 是什么呢
    6. val res2 = if (x > 0) 2 //() 相当于else ()
    7. // if ... else if ... else 代码较多时可以使用代码块{}
    8. val score = 78
    9. val res4 = {
    10. if (score > 60 && score < 70) "及格"
    11. else if (score >= 70 && score < 80) "良好" else "优秀"
    12. }
    13. println(res4) //良好
    14. }

    注:

    (1)Scala中任意表达式都是有返回值的,也就意味着if else表达式其实是有返回结果的,具体返回结果的值取决于满足条件的代码体的最后一行内容

    1. val a = 10
    2. val b = if (a>0) true else false
    3. print(b) // true

    // ( ) => Unit => void

    (2)如果大括号内的逻辑代码只有一行,大括号可以省略

    1. val a = 10
    2. if (a>0)
    3. print("a > 0")
    4. else
    5. print("a <= 0")

    2.2 while表达式

    Scala提供和Java一样的while和do循环,与If语句不同,While语句本身没有值,即整个While语句的结果是Unit类型的()。

    1. var n = 1;
    2. val while1 = while(n <= 10){
    3. n += 1
    4. }
    5. println(while1) // ()
    6. println(n) // 11
    7. var (sum, num) = (0, 100)
    8. while (num >= 0) {
    9. sum += num;
    10. num = num - 1; //scala不能num -- 步长
    11. }
    12. println(sum)

    3.3 for表达式

    if 循环守卫:引入循环保护式(也称条件判断式,守卫)。保护式为true则进入循环体内部,为false则跳过,类似于continue

    • 单层for循环
    1. for (i <- 1 to 10){
    2. println(i)
    3. }
    4. for (i <- 1 to 10 if i % 2 == 0){
    5. println(i)
    6. }
    7. var skills = Array("Hadoop", "Spark", "Storm", "Hive", "HBase", "Kafka")
    8. for (skill <- skills) {
    9. println(skill)
    10. }
    • 双重for循环
    1. //两种for循环等价
    2. for(i <- 1 to 3 ; j <- 1 to 3 ; if i != j){
    3. println((10 * i + j) + " ")
    4. }
    5. for(i <- 1 to 3){
    6. for(j <- 1 to 3){
    7. if(i != j){
    8. println((10 * i + j) + " ")
    9. }
    10. }
    11. }
    •  使用{} 替代()

    注:{}()对于for表达式来说都可以。for 推导式有一个不成文的约定:当for 推导式仅包含单一表达式时使用原括号,当其包含多个表达式时使用大括号。值得注意的是,使用原括号时,早前版本的Scala 要求表达式之间必须使用分号。

    这里的写法和前面的等价

    1. for{i <- 1 to 3 ;j <- 1 to 3 ; if i != j}{
    2. println((10 * i + j) + " ")
    3. }
    4. for{i <- 1 to 3
    5. j <- 1 to 3
    6. if i != j
    7. } {
    8. println((10 * i + j) + " ")
    9. }

    3.4 foreach表达式 

    对集合中的元素做遍历

    1. var skills = Array("Hadoop", "Spark", "Storm", "Hive", "HBase", "Kafka")
    2. skills.foreach(x => println(x))

    3.5 yeild 关键字

    循环返回值:  将遍历过程中处理的结果返回到一个新集合中,使用yield关键字

    1. val for5 = for(i <- 1 to 10 if i % 2 == 0) yield i
    2. println(for5) // Vector(2, 4, 6, 8, 10)

    4. 函数

    4.1 函数的定义和使用

    4.2 默认参数

     默认参数:在函数定义时,允许制定参数的默认值

    1. object DefaultParam extends App {
    2. def printMessage(name: String = "itcats", age: Int = 18, country: String = "中国"): Unit = {
    3. println(s"$name $age $country")
    4. }
    5. printMessage()
    6. printMessage("zp")
    7. printMessage(age = 20, country = "美国")
    8. }

    4.3 命名参数

    传统方式:实参和形参的顺序要一致

    命名参数: 定义函数参数的名字,可以不按照顺序进行传参

    1. object Function2 {
    2. def main(args: Array[String]): Unit = {
    3. //常规调用方式
    4. speed(100, 10)
    5. //命名参数调用方式1
    6. speed(distance = 100, time = 10)
    7. //命名参数调用方式2 (调换顺序)
    8. speed(time = 10, distance = 100)
    9. }
    10. //演示命名参数
    11. def speed(distance: Int, time: Int): Unit = {
    12. println(distance / time)
    13. }
    14. }

    4.4 可变参数

    • 演示可变参数 在参数类型后加一个通配符* 即可
    • 可变参数要放在参数列表中最后的位置
    1. object Function3 {
    2. def main(args: Array[String]): Unit = {
    3. println(sum(1, 2, 3, 4))
    4. }
    5. //演示可变参数 在参数类型后加一个通配符* 即可
    6. def sum(nums: Int*): Int = {
    7. var res = 0;
    8. for (num <- nums) {
    9. res += num;
    10. }
    11. res
    12. }
    13. //可变参数要放在参数列表中最后的位置
    14. def sum1(initValue: Int, nums: Int*): Int = {
    15. var res = initValue;
    16. for (num <- nums) {
    17. res += num;
    18. }
    19. res
    20. }
    21. }

    5. Scala面向对象

    5.1 类的定义和使用

    •  占位符_ 的使用只能用var,不能用val
    • var 修饰的属性会自动生成getter / setter方法
    • val 修饰的属性只会生成gettter 方法
    • private [this] 修饰的属性只能在本类中使用
    1. package com.sanqian.scala.lesson3
    2. object Test1 {
    3. def main(args: Array[String]): Unit = {
    4. //创建Person对象
    5. val person = new Person()
    6. println(person.name + " " + person.age) //null 18
    7. person.name = "小明"
    8. //person.age = 19 报错 val age 不可变
    9. println(person.name + " " + person.age) //小明 18
    10. println(person.eat) //调用person的eat()方法 小明is eating
    11. person.watchMovie("泰坦尼克号") //小明 is watching 泰坦尼克号
    12. person.printInfo //调用person中的printInfo()方法 小明的性别是 male
    13. // person.gender 报错 private [this] 所修饰的变量只能在其本类访问,故编译不通过
    14. }
    15. }
    16. //在scala中定义一个类
    17. class Person{
    18. //相当于书写了getter/setter(var)
    19. var name : String = _ //占位符_ 必须为var,不能为val,否则报错 String占位符默认为null
    20. //相当于书写了setter(val)
    21. val age : Int = 18 //也可以写成 val age = 18
    22. private [this] val gender = "male"
    23. def printInfo: Unit ={
    24. println(name + "的性别是 "+ gender) //private [this] 可以在本类Person中使用
    25. }
    26. //定义方法
    27. def eat():String = {
    28. name + "is eating"
    29. }
    30. def watchMovie(movieName : String) :Unit = {
    31. println(name + " is watching " + movieName)
    32. }
    33. }

    5.2 主构造器和附属构造器

    • 主构造器:紧跟在类后面的参数列表  val或var不可省略,否则第行student.属性(省略var或val的报错,无法访问)
    • 如果成员属性var修饰相当于对外提供getter/setter方法  val修饰相当于对外提供getter方法
    1. package com.sanqian.scala.lesson3
    2. //scala构造器演示
    3. object Constructor {
    4. def main(args: Array[String]): Unit = {
    5. val student = new Student("小明", 20)
    6. println("姓名:" + student.name + " 年龄:" + student.age + " 职业:" + student.occupation) //姓名:小明 年龄:20 职业:学生
    7. val student2 = new Student("张三", 21, "男")
    8. println("姓名:" + student2.name + " 年龄:" + student2.age + " 职业:" + student2.occupation) //姓名:小明 年龄:20 职业:学生
    9. }
    10. }
    11. //主构造器:紧跟在类后面的参数列表 val或var不可省略,否则第行student.属性(省略var或val的报错,无法访问)
    12. //如果成员属性var修饰相当于对外提供getter/setter方法 val修饰相当于对外提供getter方法
    13. class Student(val name: String, val age: Int) {
    14. println("主构造器执行")
    15. val occupation: String = "学生"
    16. var gender: String = _
    17. //附属构造器
    18. def this(name: String, age: Int, gender: String) {
    19. this(name, age) //附属构造器第一行代码必须调用主构造器或其他附属构造器
    20. this.gender = gender
    21. }
    22. println("主构造器结束")
    23. }

    私有主构造器,设置主构造器的访问权限【注意private是放在主构造器前面】 

    class Teacher private(var name: String, age: Int) {}

    私有附属构造器

    1. class Teacher(var name: String, age: Int) {
    2. var sex: String = _
    3. //私有辅助构造器
    4. private def this(name: String, age: Int, sex: String) = {
    5. //在辅助构造器中必须先调用主构造器
    6. this(name, age)
    7. this.sex = sex
    8. }
    9. }

     类的成员属性访问权限:如果类的主构造器中成员属性是private修饰的,它的getter/setter方法都是私有的

    1. class Teacher(private var name: String, age: Int) {
    2. //...
    3. }

    修饰类的访问权限,私有类private [this] class XXX 

    1. //类的前面加上private 标识这个类在当前包下都见,而且当前包下的子包不可见 默认private[this]
    2. private[this] class Teacher(var name: String, val age: Int){}
    3. //类的前面加上private[包名] 如private[itcats]表示这个类在itcats包及其子包下都可见
    4. private[itcats] class Teacher(var name: String, val age: Int){}

    5.3 继承

    • 在创建子类对象的时候,首先会执行父类的构造方法
    • 从父类继承过来的属性,在子类主构造器中不需要写val/var 
    1. object ExtendApp {
    2. def main(args: Array[String]): Unit = {
    3. var an = new Bird("鹦鹉",2,"黑色")
    4. println(an.name + " "+an.age + " "+ an.color)
    5. }
    6. }
    7. //父类主构造器
    8. class Animal(val name: String, val age: Int) {
    9. println("Animal Constructor in")
    10. println("Animal Constructor out")
    11. }
    12. //子类主构造
    13. //这里需要注意,从父类继承过来的name,age,在子类主构造器中不需要写var/val , 而color没有继承过来,必须要写var/val
    14. class Bird(name: String, age: Int, val color: String) extends Animal(name, age) {
    15. println("Bird Constructor in")
    16. println("Bird Constructor out")
    17. }

    5.4 重写

    • 对于父类已有的属性和方法,子类重写需要加上override关键字
    1. package com.sanqian.scala.lesson2
    2. //重写
    3. object OverwriteApp {
    4. def main(args: Array[String]): Unit = {
    5. var apple = new Apple("iPhone Xs",4999.9,"黑色")
    6. println(apple.toString)
    7. }
    8. }
    9. //父类主构造器
    10. class Phone(var name: String, val price: Double) {
    11. val country = "中国" //注意: 此处必须为val类型
    12. }
    13. //子类主构造
    14. //这里需要注意,从父类继承过来的name,age,在子类主构造器中不需要写var/val , 而color没有继承过来,必须要写var/val
    15. class Apple(name: String, price: Double, val color: String) extends Phone(name, price) {
    16. //重写父类的name属性
    17. override val country = "美国" //val country = "美国"报错,必须要加override关键字,并且必须为val 类型 否则将会显示mutable变量不可改变的错误
    18. //重写toStirng()方法
    19. override def toString() : String = {
    20. "name = " + name +" , price = "+ price+" , "+"color = " +color+" , "+"country = " + country
    21. }
    22. }

     5.5 抽象类

    1. 抽象类使用abstract关键字修饰,且抽象类中[属性、方法]可以有具体的实现,也可以没有具体的实现
    2. 抽象类没有被实例化不能使用new创建对象
    1. package com.sanqian.scala.lesson4
    2. object AbstractApp {
    3. def main(args: Array[String]): Unit = {
    4. // new Person() // 抽样类没有被实例化,不能创建对象
    5. val student = new Student3()
    6. println(student.name)
    7. student.speak
    8. }
    9. }
    10. /**
    11. * 类的一个或多个属性、方法没有完整的实现(只有定义,没有实现)
    12. */
    13. abstract class Person {
    14. def speak
    15. val name: String
    16. val age: Int
    17. }
    18. class Student3 extends Person{
    19. override def speak: Unit = {
    20. print("speak...")
    21. }
    22. override val name: String = "zhangsan"
    23. override val age: Int = 22
    24. }

     5.6 伴生类和伴生对象

    1.  如果有一个class,还有一个与class同名的object,那么就称这个object时class的伴生对象,class是object的伴生类
    2. 在 Scala 中,是没有 static 这个东西的,但是它也为我们提供了单例模式的实现方法,那就是使用关键字 object。object中定义的成员变量和方法都是静态的
    3. Scala 中使用单例模式时,除了定义的类之外,还要定义一个同名的 object 对象,它和类的区别是,object对象不能带参数。
    4. 类和它的伴生对象可以互相访问其私有成员方法和属性
    5. 伴生对象可以访问类中的私有方法private,不能访问private[this]修饰的成员变量即方法
    1. package com.sanqian.scala.lesson4
    2. object ApplyApp {
    3. def main(args: Array[String]): Unit = {
    4. // for(i <- 1 to 10){
    5. // ApplyTest.incr
    6. // }
    7. // print(ApplyTest.count) // 10, 说明object 本身就是一个单例对象
    8. val b = ApplyTest() // ==> Object.apply
    9. val c = ApplyTest() // ==》Object.apply
    10. c() // Class.apply
    11. // 面试重点,结论:
    12. // 类名() ==> Object.apply
    13. // 对象() ==> Class.apply
    14. }
    15. }
    16. //伴生类
    17. class ApplyTest{
    18. def apply() = {
    19. println("class ApplyTest apply...")
    20. }
    21. }
    22. //伴生对象
    23. object ApplyTest{
    24. println("object ApplyTest enter....")
    25. var count = 0
    26. def incr = {
    27. count += 1
    28. }
    29. // 最佳实践: 在Object的中apply方法中去new Class
    30. def apply(): ApplyTest = {
    31. println("Object ApplyTest apply...")
    32. new ApplyTest()
    33. }
    34. println("object ApplyTest leave....")
    35. }

    输出:

    object ApplyTest enter....
    object ApplyTest leave....
    Object ApplyTest apply...
    Object ApplyTest apply...
    class ApplyTest apply...

    面试重点,结论:
        // 类名() ==> 调用Object.apply
        // 对象() ==> 调用Class.apply

    最佳实践: 在Object的中apply方法中去new Class

     5.7 case class 

    1. 与普通类的区别是不用new,可以直接调用
    2. 通常用在模式匹配
    1. object CaseClassAPP {
    2. def main(args: Array[String]): Unit = {
    3. println(Dog("wangcai").name)
    4. }
    5. }
    6. case class Dog(name: String)

    5.8 Trait

    1. Scala Trait(特征) 作用相当于 Java 的接口,实际上它比接口还功能强大。与接口不同的是,它还可以定义属性和方法的实现。
    2. 一般情况下Scala的类只能够继承单一父类,但是如果是 Trait(特征) 的话就可以继承多个,从结果来看就是实现了多重继承。
    3. 如果特质中trait某个方法有具体的实现,在子类继承重写的时候必须使用override关键字。如果特质方法没有具体的实现,子类在实现的时候可以不加override关键字也可以加

     一个类可以继承多个特质使用with进行连接

    总结:

    1、类与对象都可以混入一个或多个特质

    2、特质中可以定义有具体实现的方法和没有具体实现的方法

    3、如果一个类或者一个对象(继承)混入了某一个特质,这个特质中有一个未被实现的方法A和一个已实现的方法B

    这个类或对象必须实现这个没有实现的方法A,且可选择性的重写方法B,必须使用override关键字。

    提问:Scala中特质trait与抽象类abstract的区别?

    优先使用特质trait。一个类扩展多个特质trait是很方便的,但却只能扩展一个抽象类。
    如果你需要构造函数参数,使用抽象类。因为抽象类可以定义带参数的构造函数,而特质不行。例如:
    trait t(i: Int) {},参数i是非法的。

     6. Scala集合

    1. Scala同时支持可变集合(比如Java中的ArrayList , 长度可以动态改变)和不可变集合(比如Java中的数组,一旦初始化长度不可改变),不可变集合从不可变,可以安全的并发访问。

    2. 两个主要的包:

    不可变集合:scala.collection.immutable (默认使用)

    可变集合:  scala.collection.mutable

    3. Scala默认采用不可变集合,对于几乎所有的集合类,Scala都同时提供了可变和不可变的版本。

    4. Scala 的集合有三大类:序列 Seq、集 Set、映射 Map,所有的集合都扩展自 Iterable 特质 在 Scala 中集合有可变(mutable)和不可变(immutable)两种类型,immutable 类型的集合 初始化后就不能改变了(注意与 val 修饰的变量进行区别)

    • 5. 不可变集合的继承层次
    •  6. 可变集合的继承层次 : 略

    6.1 定长数据Array

    •  使用new 的方式创建数据不够优雅,可以使用下面这种

    • 其他操作: 求和、最大值、最小值、打印

     6.2 可变数组ArrayBuffer 

    • 可变数组:长度可变、内容可变

    • 可变数组与不可变数组的转换
    1. arr1.toBuffer
    2. arr2.toArray

    • 遍历数组 

    两种方式

    • 反转打印数组

     6.3 定长List

    1. Nil就是一个空的list
    2. l.head : 获取第一个元素
    3. l.tail : 获取除第一个元素之外其他元素
    4. 使用:: 合并List()数组

     6.3 可变List

    • 增加元素

    • 减少元素 

     

    •  可变List转定长List

     

    • 实现一个求和( :_* 可把Seq转换成可变参数)

     

     6.4 Set

    1. set 是一个无序的不重复的集合
    2. 可变Set   collection.mutable.HashSet
    1. scala> val hset = collection.mutable.HashSet(1,3,4)
    2. hset: scala.collection.mutable.HashSet[Int] = Set(1, 3, 4)
    3. scala> val set = Set(1,2,3,3)
    4. set: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
    5. scala> hset.add(5)
    6. res26: Boolean = true
    7. scala> hset
    8. res27: scala.collection.mutable.HashSet[Int] = Set(1, 5, 3, 4)
    9. scala> hset.add(1)
    10. res28: Boolean = false
    11. scala> hset.remove(1)
    12. res29: Boolean = true
    13. scala> hset.remove(999)
    14. res30: Boolean = false
    15. scala> hset.-=(3)
    16. res31: hset.type = Set(5, 4)
    17. scala> hset ++ Set(0,9) //++ 原集合数值无变化
    18. res33: scala.collection.mutable.HashSet[Int] = Set(0, 9, 5, 4)
    19. scala> hset ++= Set(0,9) //++=原集合数据发生变化
    20. res34: hset.type = Set(0, 9, 5, 4)

    7. 模式匹配

    7.1 最基础的模式匹配

    1. object BaseMatch {
    2. val a: Array[String] = Array("a,", "b", "c", "d")
    3. val name: String = a(Random.nextInt(a.length))
    4. name match {
    5. case "a" => println("This is a")
    6. case "b" => println("This is b")
    7. case "c" => println("This is c")
    8. case "d" => println("This is d")
    9. case _ => println("Can not find it")
    10. }
    11. def matchMethod(num : Int) :String = num match {
    12. case 1 => "This is a"
    13. case 2 => "This is b"
    14. case 3 => "This is c"
    15. case 4 => "This is d"
    16. case 4 => "This is e"
    17. case _ => "Can not fiSnd it"
    18. }
    19. def main(str: Array[String]): Unit = {
    20. //一旦匹配上就直接退出模式匹配
    21. matchMethod(4) //返回是"This is d"
    22. }
    23. }

    7.2 加条件进行匹配

    1. object BaseMatch extends App {
    2. print(matchMethod("haha",4)) //This is d
    3. def matchMethod(keyword: String, num: Int): String = num match {
    4. case 1 => "This is a"
    5. case 2 => "This is b"
    6. case 3 => "This is c"
    7. case 4 if (keyword == "haha") => "This is d" // 双重过滤
    8. case _ => "Can not fiSnd it"
    9. }
    10. }

    7.3 Array模式匹配
     

    1. def who(arr : Array[String]): Unit = arr match {
    2. //只匹配数组中含有一个"zhangsan"的case
    3. case Array("zhangsan") => println("This is zhangsan")
    4. case Array("zhangsan","lisi") => println("This is zhangsan and lisi")
    5. //匹配数组中只含三个元素的case(对元素没有要求)
    6. case Array(x,y,z) => println("This is x,y,z")
    7. //匹配第一个为wangwu,后可有可无任意多个元素的case
    8. case Array("wangwu",_*) => println("This is wangwu and others")
    9. case _ => println("who is it?")
    10. }

    7.4 List模式匹配

    与Array的模式匹配十分相似

    1. def whoList(list : List[String]): Unit = list match {
    2. //只匹配数组中含有一个"zhangsan"的case
    3. case "zhangsan"::Nil => println("This is zhangsan")
    4. case "zhangsan"::"lisi"::Nil => println("This is zhangsan and lisi")
    5. //匹配数组中只含三个元素的case(对元素没有要求)
    6. case x::y::z::Nil => println("This is x,y,z")
    7. //匹配第一个为wangwu,后可有可无任意多个元素的case
    8. case "wangwu"::tail => println("This is wangwu and others")
    9. case m :: n => println("匹配拥有head,tail的List集合")
    10. case _ => println("who is it?")
    11. }

    7.5 类型匹配

    1. //类型模式匹配
    2. matchType(Map("haha" -> "hehe"))
    3. def matchType(obj : Any): Unit = {
    4. obj match{
    5. case x:Int => println("Int")
    6. case y:String => println("String")
    7. case z:Map[_,_] => z.foreach(println)
    8. case _ => println("unkown")
    9. }
    10. }

    7.6 Scala异常处理

    1. //Scala中的异常处理
    2. object MyException extends App {
    3. try{
    4. val i = 1 / 0; //制造异常
    5. }catch {
    6. case e:ArithmeticException => println("除数不能为0")
    7. case e:Exception => println("出现了未知异常")
    8. }finally {
    9. println("关闭资源处理")
    10. }
    11. }

    7.7 case class 模式匹配

    1. object CaseClassMatch extends App {
    2. def caseMatch(plane : Plane): Unit = plane match {
    3. case Boeing(name: String, age: Int) => println("This is boeing 787 , age is 2")
    4. case Airbus(name: String, age: Double) => println("This is airbus 330 , age is 0.8")
    5. case Other(name: String, age: Int) => println("This is 战斗机 , age is 7")
    6. }
    7. caseMatch(Boeing("播音787",2))
    8. caseMatch(Airbus("空客330",0.8))
    9. caseMatch(Other("战斗机",7))
    10. }
    11. class Plane
    12. case class Boeing(name: String, age: Int) extends Plane {}
    13. case class Airbus(name: String, age: Double) extends Plane {}
    14. case class Other(name: String, age: Int) extends Plane {}

    8. Scala高级函数
     

    8.1 字符串高级操作

    1. 字符串的插值:'s'允许在处理字符串时直接使用变量,可以加{} 也可以不加{}
    2. 多行字符串的表示: 使用三引号""" """ (与python用法相同)
    1. object StringApi extends App {
    2. val name = "itcats_cn"
    3. val job = "student"
    4. val age = 999.999d
    5. //普通输出 加了, 会自动产生一个()
    6. println("name=" + name, "job=" + job) //输出结果 (name=itcats_cn,job=student)
    7. // 文字'f'插值器允许创建一个格式化的字符串,类似于 C 语言中的 printf。
    8. // 在使用'f'插值器时,所有变量引用都应该是 printf 样式格式说明符,如%d,%i,%f 等。
    9. println(f"姓名: $name%s 年龄: $age%1.2f 职业: $job") // 该行输出有换行
    10. printf("姓名: %s 年龄: %1.2f 职业: %s", name, age, job) // 该行输出没有换行
    11. // 's'允许在处理字符串时直接使用变量。
    12. // 在println语句中将String变量($name)附加到普通字符串中。
    13. println()
    14. println(s"姓名: ${name} 年龄: $age 职业: $job") //可以{}也可以不{}
    15. // 字符串插入器还可以处理任意表达式。
    16. // 使用's'字符串插入器处理具有任意表达式(${1 + 1})的字符串(1 + 1)的以下代码片段。 任何表达式都可以嵌入到${}中。
    17. println(s"1 + 1 = ${1 + 1}") // 1 + 1 = 2
    18. //多行字符串演示(连续输入三个"后按回车)
    19. val c =
    20. """
    21. |Hello
    22. |World
    23. """.stripMargin
    24. println(c)
    25. }

    8.2 匿名函数

    匿名函数: 函数是可以命名的,也可以不命名
    语法: (参数名: 参数类型...) => 函数体

    1. //匿名函数:函数是可以命名也可以匿名的
    2. object AnonymityApp extends App {
    3. //命名函数定义
    4. def hello(name: String): Unit = {
    5. println(s"Hello : $name")
    6. }
    7. //匿名函数可以传递给变量
    8. val f = (name:String) => println(s"Hello : $name")
    9. //也可以传递给函数
    10. def an = (name:String) => println(s"Hello : $name")
    11. //调用
    12. hello("a")
    13. f("b")
    14. an("c")
    15. }

    8.3 currying函数(柯里化函数)

     柯里化: 将接收一个参数的函数,转换成2个

    1. object CurryApp extends App {
    2. //curry函数:将原来接收两个参数的一个函数,转换成2个
    3. //原函数写法
    4. def sum(a: Double, b: Double): Double = {
    5. a + b
    6. }
    7. //curry函数
    8. def currySum(a: Double)(b: Double): Double = {
    9. a + b
    10. }
    11. //柯里化的演变过程
    12. def add(x: Int) = (y: Int) => x + y //(y: Int) => x + y 为一个匿名函数,
    13. //也就意味着 add 方法的返回值为一个匿名函数
    14. //高阶函数,方法的参数是函数或方法的返回值是函数的函数
    15. //调用
    16. println( sum(1,1) )
    17. println( currySum(1)(1) )
    18. }

    8.4 高阶函数

    map :逐个去操作集合中的每个元素

    1. object HighLevelFunction extends App {
    2. val l = List(1, 2, 3, 4, 5)
    3. //1.map 逐个操作集合里面的每个元素 实际上是建立一种映射关系,返回的是一个新的数组
    4. l.map((x: Int) => x + 1) //将List内的每个元素(x:Int) + 1
    5. l.map(x => x + 1) //scala能帮我们推断出List内每个元素是Int,且只有一个元素时候,括号可以省略
    6. l.map(_ + 1) //对List中的任意元素都 + 1
    7. //遍历
    8. l.map(_ + 1).foreach(print) //23456 List[Int]
    9. println()
    10. println("-------------")
    11. //2.在map取出每个元素 + 1的基础上,使用filter过滤出 < 4的数字
    12. l.map(_ + 1).filter(_ < 4).foreach(print) //23 List[Int]
    13. println()
    14. println("-------------")
    15. //3.使用take取集合中的前3个元素
    16. l.take(3).foreach(print) //123 List[Int]
    17. println()
    18. println("-------------")
    19. //4.reduce
    20. print( l.reduce(_ + _) ) //15 Int 将l集合中的前后元素两两相加 1+2 3+3 6+4 10+5
    21. println()
    22. println("-------------")
    23. //5.reduceLeft = reduce
    24. print( l.reduceLeft(_ - _) ) //-13 1 - 2 - 3 - 4 - 5 = -13
    25. println()
    26. println("-------------")
    27. //6.reduceRight
    28. print( l.reduceRight(_ - _) ) //3 ( 1 - ( 2 - ( 3 - ( 4 - 5 ))))
    29. println()
    30. println("-------------")
    31. //7.fold(第一个括号代表初始值)
    32. print( l.fold(0)(_ - _) ) //-15 0-1-2-3-4-5 = -15
    33. println()
    34. println("-------------")
    35. //8.foldLeft = fold (0在最左边)
    36. print( l.foldLeft(0)(_ - _)) //-15 0-1-2-3-4-5 = -15
    37. println()
    38. println("-------------")
    39. //9.foldRight (0在最右边)
    40. print( l.foldRight(0)(_ - _) ) //3 ( 1 - ( 2 - ( 3 - ( 4 - (5 - 0) ) ) ) )
    41. println()
    42. println("-------------")
    43. //10.flatten
    44. val f = List(List(1,2),List(3,4),List(5,6)) //List内部是一个List类型的元祖
    45. print(f.flatten) //flatten可以理解为压扁 List(1, 2, 3, 4, 5, 6)
    46. //11.flatMap(可以理解为map + flatten)
    47. println()
    48. println("-------------")
    49. //先来看一个例子,将f中List元祖都扩大两倍(使用map) 第一次使用map取出来的是List(x,y) 第二次用map取出来的是(x,y)
    50. print(f.map(_.map(_ * 2))) //List(List(2, 4), List(6, 8), List(10, 12))
    51. println()
    52. println("-------------")
    53. //flatMap所实现的效果是 List(2, 4, 6, 8, 10, 12)
    54. print(f.flatMap(_.map(_ * 2)))
    55. println()
    56. println("-------------")
    57. //12.flatMap的一些应用
    58. val t = List("hello,hello,world,hello")
    59. // t.flatMap(_.split(",")) List(hello, hello, world, hello)
    60. t.flatMap(_.split(",")).map(x => (x,1)).foreach(println)
    61. /**
    62. * 输出:
    63. * (hello,1)
    64. (hello,1)
    65. (world,1)
    66. (hello,1)
    67. */
    68. }

    并行聚合 

    1. scala> list.aggregate
    2. def aggregate[B](z: => B)(seqop: (B, Int) => B,combop: (B, B) => B): B
    3. scala> list.aggregate(0)(_ + _ , _ + _)
    4. res6: Int = 10

    并集union 

    1. scala> list
    2. res7: List[Int] = List(1, 2, 3, 4)
    3. scala> val list1 = List(1,6)
    4. list1: List[Int] = List(1, 6)
    5. scala> list.union(list1)
    6. res20: List[Int] = List(1, 2, 3, 4, 1, 6)

    交集intersect

    1. scala> list.intersect(list1)
    2. res21: List[Int] = List(1)

    差集diff

    1. scala> list.diff(list1)
    2. res22: List[Int] = List(2, 3, 4)

    角标元素合并组合成元组zip

    1. scala> list
    2. res23: List[Int] = List(1, 2, 3, 4)
    3. scala> list1
    4. res24: List[Int] = List(1, 6)
    5. scala> list.zip(list1)
    6. res25: List[(Int, Int)] = List((1,1), (2,6))

    9. Scala隐式转换

    10. Scala操作外部数据

    包括文件、网络数据、MySQL、XML等外部数据

    10.1 操作文件/网络资源

    1. //使用scala操作File文件
    2. object FileTest {
    3. def main(args: Array[String]): Unit = {
    4. //读取文件
    5. var file = scala.io.Source.fromFile("/Users/fatah/Desktop/1.txt")(scala.io.Codec.UTF8);
    6. //var file = scala.io.Source.fromFile("/Users/fatah/Desktop/1.txt");
    7. def readLine(): Unit = {
    8. for (line <- file.getLines()) {
    9. println(line)
    10. }
    11. }
    12. //调用读取文件资源
    13. //readLine
    14. //调用读取网络资源
    15. readNet
    16. //读取网络数据
    17. def readNet(): Unit ={
    18. var file = scala.io.Source.fromURL("https://www.baidu.com");
    19. for(line <- file.getLines()){
    20. println(line)
    21. }
    22. }
    23. }
    24. }

    10.2 操作XML

    10.3 操作MySQL

    1. //使用scala连接数据库,操作MySQL
    2. object MySQLTest {
    3. def main(args: Array[String]): Unit = {
    4. //书写连接数据库相关信息
    5. val url = "jdbc:mysql://localhost:3306/crash_course"
    6. val username = "root"
    7. val password = "root"
    8. //在scala中这一步与Java的class.forName写法有所不同
    9. try {
    10. classOf[com.mysql.jdbc.Driver]
    11. val conn = DriverManager.getConnection(url,username,password)
    12. val sql = "select * from orders"
    13. val stmt = conn.prepareStatement(sql)
    14. val rs = stmt.executeQuery();
    15. while(rs.next()){
    16. val order_num = rs.getString("order_num")
    17. val order_date = rs.getString("order_date")
    18. val cust_id = rs.getString("cust_id")
    19. println(s"$order_num , $order_date , $cust_id")
    20. }
    21. }catch {
    22. case e : Exception => e.printStackTrace()
    23. }finally {
    24. //关闭资源,懒得关了,懂就行
    25. }
    26. }
    27. }

  • 相关阅读:
    使用Shiro实现权限验证
    在k8s上部署dolphinscheduler
    聊聊Flink的必知必会(一)
    SpringBoot-16-模块开发-首页登陆并权限拦截
    【限时福利】21天学习挑战赛 - MySQL从入门到精通
    阿里云文件验证方式申请SSL证书的教程
    shell_42.Linux移动参数
    ProNas-振动噪声工程界新一代的前沿技术
    【C++】类的声明 与 类的实现 分开 ① ( 类的声明 与 类的实现 常用用法 | Visual Studio 2019 中创建类的头文件和源文件 | 确保头文件包含一次 )
    【C++】笔试训练(五)
  • 原文地址:https://blog.csdn.net/anglemanyi/article/details/126943855