Scala详解(1)

Scala

简介

概述
  1. Scala是Martin Ordersky(马丁.奥德斯科/基)于2001年开始设计的一门支持面向对象(Object-oriented)和函数式编程(Functional Programming)的多范式语言

  2. Scala的官网:www.scala-lang.org

  3. Scala目前为止有3个大版本:Scala1.X~3.X。目前Scala1.X已经停止使用,Scala3.x兼容Scala2.x的所有特性,但是Scala3.x从2021年才推出的版本,也因此,目前大数据中的主流框架Spark、Flink等基本上是基于Scala2.x实现的,所以上课阶段使用Scala2.x

  4. Scala语言即支持脚本方式来运行,也支持编译之后执行。Scala也是通过JVM来编译的,所以Scala代码编译完成之后依然产生的是.class文件,也因此Scala定义的逻辑可以在Java中执行,同样,Java中所有的类都可以被Scala调用

  5. 安装Scala之前,需要先安装JDK1.8

特点

  1. Scala是一门多范式编程语言,支持面向对象和函数式编程两种方式。目前市面上的编程语言可以分为四类:面向对象、面向过程、函数式、泛型式

  2. Scala是一门静态类型(强类型)的编程语言,在编译的时候就需要确定数据类型,定义之后类型不能更改

  3. Scala是一门基于JVM的编程语言,所以和Java是互通的

  4. 相对于Java代码而言,Scala会更加的优雅和简洁

基本语法

注意问题

  1. 在Scala中,认为换行就是新的一行语句,所以省略分号不写

  2. 主函数必须定义到伴生对象object中

  3. Scala的注释方式和Java的注释方式是一模一样的,支持单行注释、多行注释和文档注释

  4. 在Scala中,一共有39个关键字,其中大部分关键字是Java是重合的,例如packageclassfor等,但是Scala同时提供了自有的关键字,例如objectdefyieldvarvalimplicit

标识符命名规则

  1. 由字母、数字和下划线组成

  2. 数字不能开头

  3. 不能使用关键字

  4. 严格区分大小写

  5. 可以使用符号作为标识符,但是如果使用符号作为标识符,那么整个标识符必须全部使用符号

  6. 可以使用反引号来将任意字符串标记为标识符

变量和常量

  1. 变量的定义规则

    var 变量名:数据类型 = 数据
  2. 常量的定义规则

    val 常量名:数据类型 = 数据
  3. 在Scala中,推荐使用常量

  4. 因为Scala是一门强类型语言,所以变量/常量在赋值之后,数据类型就不能发生变化,因此Scala中,可以根据值自动推导数据类型,所以定义变量/常量的时候,数据类型可以省略

  5. 除非值的类型和声明类型不完全一致,此时才需要显式声明

  6. 不同于Java的地方在于,不支持变量先声明后赋值

控制台输入输出

类型转换

运算符

流程控制

判断结构

循环结构

while循环

for循环

循环守卫式

循环的嵌套

变量引入

循环的返回值

倒叙遍历
package com.fesco.loop
​
import scala.language.postfixOps
​
object LoopDemo4 {
​
  def main(args: Array[String]): Unit = {
​
    val arr = Array(5, 1, 4, 7, 8)
    val maxIndex = arr.length - 1
    // 正序遍历
    for (i <- 0 to maxIndex) println(arr(i))
    println("=" * 50)
​
    // 倒序遍历
    // 方式一
    for (i <- maxIndex to(0, -1)) println(arr(i))
    println("=" * 50)
    // 方式二
    for (i <- maxIndex to 0 by -1) println(arr(i))
    println("=" * 50)
    // 方式三
    for (i <- 0 to maxIndex reverse) println(arr(i))
  }
​
}
循环控制

  1. 在Scala中,推荐使用scala.io.StdIn来从控制台获取数据

  2. 在Scala中,可以使用print或者println来进行输出。println是输出并换行

  3. 如果需要输出多个数据,可以使用+来进行字符串的拼接

    println("name:" + name + ", age:" + age + ", gender:" + gender)
  4. Scala中还提供了占位符的方式来输出数据

    printf("name:%s, age:%d, gender:%s\n", name, age, gender)
  5. Scala中还提供了数据的引用形式

    println(s"name:$name, age:$age, gender:$gender")
  6. 如果需要保留小数位(精确),那么此时需要以f作为开头

    println(f"total:${price * weight}%3.2f")
  7. 字符串中支持转义字符

    // 字符串中支持转义字符
    println("hello\tworld")
    // 原样输出字符串
    println(raw"hello\tworld")
  8. 输出多行组成的字符串

    val sql =
          """
             |select name,
             |   sum(score)
             |from students
             |group by name;
          """.stripMargin
    println(sql)

    Scala

    基础语法

    数据类型

    概述
  9. 在Java中,基本类型、static等都不符合面向对象的规则。Scala作为一门完全面向对象的语言,不支持基本类型、static等

  10. 在Scala中,提供了公共父类:Any,即所有的类都是Any的子类

    1. Any下分为了两个大的子类:AnyVal(任意数值)和AnyRef(任意引用)。无论AnyVal还是AnyRef都是类

    2. AnyVal包含了常用的数据类型

      1. 例如:ByteShortIntLongFloatDoubleCharBoolean

      2. Unit:对应了Java中的void。当一个函数没有返回值的时候,返回值类型就是UnitUnit只包含了一个对象,就是()

      3. StringOps:字符串,是对Java中的String类做了增强

    3. 除了AnyVal以外的其他的类都是AnyRef的子类

      1. AnyRef包含Scala中的类和Java中的类

      2. AnyRef中提供了特殊子类:NullNull是任意AnyRef类中的子类。Null只有一个值就是null

  11. 不同于Java的地方在于,Scala中还提供了公共子类:Nothing,即所有的类都是Nothing的父类

  12. 在Scala中,整数默认为Int,小数默认为Double

  13. 和Java中,在Scala中,数据类型转换也分为隐式(自动)和显式(强制)

  14. 所有的强制类型转换需要通过toxxx函数来转换

    // 显式转换
    val a = 5L
    val c: Int = a.toInt
    println(c)
    val x = 5.38
    val y = x.toFloat
    println(y)
  15. Scala中提供了五大类运算符:算术、赋值、比较、逻辑、位

  16. 需要注意的是,Scala中没有提供三元运算符(?:)

  17. Scala中没有自增(++)和自减(--)运算

  18. Scala中还不支持连等定义和连等赋值

    var x = 5
    // 错误写法
    x += x -= 3
  19. 在Scala中,没有基本类型的说法,所有的数据都是对象,因此所有的运算符本质上都是函数

    val x = 3
    val y = 5
    // 所有的运算符本质上都是函数
    val r1 = x.+(y)
    println(r1)
    // 调用函数的时候,.可以省略不屑
    val r2 = x + (y)
    println(r2)
    // 当调用函数中只有一个参数的时候,可以省略()不屑
    val r3 = x + y
    println(r3)
  20. 同Java一样,Scala中提供了ifif-elseif-else if结构,语法和Java也是一样的

  21. 案例

    package com.fesco.ifx
    ​
    import scala.io.StdIn
    ​
    object IfDemo {
    ​
      def main(args: Array[String]): Unit = {
    ​
        // 输入一个数字,判断是奇数还是偶数
        // 获取数字
        val n = StdIn.readInt()
        // 判断是奇数还是偶数
        if (n % 2 == 1) println(s"${n}是一个奇数")
        else println(s"${n}是一个偶数")
    ​
      }
    ​
    }
  22. 案例

    package com.fesco.ifx
    ​
    import scala.io.StdIn
    ​
    object IfElseIfDemo {
    ​
    ​
      def main(args: Array[String]): Unit = {
    ​
        // 案例:输入数字表示用电费,来计算电费
        // 2820 -> 0.54
        // 4800 -> 0.69
        // >4800 -> 0.89
        // 用电量
        val n = StdIn.readInt()
        // 计算一共需要缴费多少
        if (n <= 2820) println(s"${n * 0.54}")
        else if (n <= 4800) print(s"${2820 * 0.54 + (n - 2820) * 0.69}")
        else println(s"${2820 * 0.54 + 1980 * 0.69 + (n - 4800) * 0.89}")
    ​
      }
    ​
    }
  23. 和Java中不太一样的地方在于,Scala中任何结构都应该有计算结果,即任何结构都应该由返回值 - 因此,判断结构也应该有返回值,返回值默认就是代码块的最后一行

    package com.fesco.ifx
    ​
    import scala.io.StdIn
    ​
    object IfDemo2 {
    ​
      def main(args: Array[String]): Unit = {
    ​
        // 案例:输入两个数,输出较大的那个数字
        val a = StdIn.readInt()
        val b = StdIn.readInt()
    ​
        val max = if (a > b) a else b
        println(max)
    ​
      }
    ​
    }
  24. Scala中同样提供了while结构

    while(条件){
        代码块
    }
  25. 在Scala中任何结构都应该有计算结果,因此while结构也应该有计算结果,结果类型固定是Unit

  26. 案例

    package com.fesco.loop
    ​
    object WhileDemo {
    ​
      def main(args: Array[String]): Unit = {
    ​
        // 记录和
        var sum = 0
        // 变量
        var i = 1
        val r: Unit = while (i <= 100) {
          sum += i
          i += 1
        }
        println(sum)
        println(r)
    ​
      }
    ​
    }
  27. Scala中提供了for循环,但是Scala中的for循环和Java中不同,提供了for-tofor-until和循环守卫式/判断式/条件式

  28. for-to语法

    for(变量 <- 起始值.to(结束值)){
        代码块
    }
    // 或者
    for(变量 <- 起始值 to 结束值){
        代码块
    }
    // x <- a to b,表示a≤x≤b

    指定步长

    for(变量 <- 起始值.to(结束值, 步长)){
        代码块
    }
    // 或者
    for(变量 <- 起始值.to(结束值).by(步长)){
        代码块
    }
  29. 案例

    package com.fesco.loop
    ​
    object ForDemo1 {
    ​
      def main(args: Array[String]): Unit = {
    ​
        // 打印1-10
        for (n <- 1.to(10)) println(n)
        // .可以省略,如果只有1个参数,()也可以省略
        for (n <- 1 to 10) println(n)
        // 打印10以内的偶数
        for (n <- 0.to(10, 2)) println(n)
        for (n <- 0 to(10, 2)) println(n)
        for (n <- 0.to(10).by(2)) println(n)
        for (n <- 0 to 10 by 2) println(n)
    ​
      }
    ​
    }
  30. 案例

    package com.fesco.loop
    ​
    import scala.io.StdIn
    ​
    object ForDemo2 {
    ​
      def main(args: Array[String]): Unit = {
    ​
        // 案例一:输出m行n列的*组成的矩形
        val m = StdIn.readInt()
        val n = StdIn.readInt()
        for (i <- 1 to m) println("*" * n)
        println("=" * 50)
        // 案例二:输出m行*组成的三角形
        for (i <- 1 to m) println("*" * i)
        println("=" * 50)
        // 案例三:输出m行*组成的三角形
        for (i <- 1 to m) {
          // 打印空格
          print(" " * (m - i))
          // 打印*
          println("*" * (2 * i - 1))
        }
    ​
      }
    ​
    }
  31. for-until结构和for-to结构一样,区别就在于

    a to b表示a≤x≤b
    a until b表示a≤x<b
  32. 循环守卫式又称之为循环条件式或者循环判断式

  33. 当在循环中直接嵌套了一个判断结构的时候,那么此时可以将判断条件紧跟循环来执行,当满足判断条件的时候,才能进入循环执行,构成了循环守卫式

    package com.fesco.loop
    ​
    object ForDemo3 {
    ​
      def main(args: Array[String]): Unit = {
    ​
        // 打印:100以内是5的倍数,但不是7的倍数的数字
        for (i <- 0 until 100 by 5) {
          if (i % 7 != 0) {
            println(i)
          }
        }
        // 在循环中直接嵌套了一个if判断
        // 实际上需要满足条件,才会继续执行
        // 循环守卫式
        println("*" * 50)
        // 将条件紧跟循环之后,只有满足条件才会进入循环
        // 如果不满足条件,那么就继续递增直到结束
        for (i <- 0 until 100 by 5 if i % 7 != 0)
          println(i)
        // 或者
        for (i <- 0 until(100, 5) if i % 7 != 0)
          println(i)
    ​
      }
    ​
    }
  34. 在Scala中,支持循环的嵌套

    package com.fesco.loop
    ​
    object LoopDemo {
    ​
      def main(args: Array[String]): Unit = {
    ​
        // 打印九九乘法表
        for (i <- 1 to 9) {
          // 控制列
          for (j <- 1 to i) {
            print(s"$j*$i=${i * j}\t")
          }
          // 换行
          println()
        }
    ​
      }
    ​
    }
  35. 特殊形式

    package com.fesco.loop
    ​
    object LoopDemo2 {
    ​
      def main(args: Array[String]): Unit = {
    ​
        for (i <- 1 to 5) {
          for (j <- 1 to 3) {
            print(s"$i, $j\t")
          }
        }
        println()
        // 方式一:将内外循环合并成1个
        for (i <- 1 to 5; j <- 1 to 3) {
          print(s"$i, $j\t")
        }
        println()
        // 在Scala中,尽量的避免使用分号,推荐换行来表示不同的语句
        for {
          i <- 1 to 5
          j <- 1 to 3
        } {
          print(s"$i, $j\t")
        }
    ​
      }
    ​
    }
  36. 类似于循环守卫式和循环嵌套,for循环还支持变量的引入

  37. 案例

    package com.fesco.loop
    ​
    import scala.io.StdIn
    ​
    object LoopDemo3 {
    ​
      def main(args: Array[String]): Unit = {
    ​
        // 输入一个数字n,输出这个数字拆分的求和形式
        // 例如输入数字8
        // 拆分成1+7 2+6 3+5 4+4
    ​
        // 获取数字
        val n = StdIn.readInt()
    ​
        // 拆分
        for (i <- 1 to (n / 2)) {
          val j = n - i
          println(s"$n=$i+$j")
        }
        println("*" * 50)
    ​
        // 在循环中直接嵌套了一个变量j,然后后续操作变量j
        for (i <- 1 to (n / 2); j = n - i)
          println(s"$n=$i+$j")
        println("*" * 50)
        
        // 在Scala中,推荐换行来写新语句
        for {
          i <- 1 to (n / 2)
          j = n - i
        } {
          println(s"$n=$i+$j")
        }
    ​
      }
    ​
    }
  38. 在Scala中所有的结构都应该有计算结果,因此循环也必须有计算结果。其中while和do-while的结果类型只能是Unit,而for循环默认的结果类型也是Unit,但是for循环可以通过yield关键字将计算结果放入一个Vector中返回

  39. 案例

    package com.fesco.loop
    ​
    import java.util
    import scala.io.StdIn
    ​
    object YieldDemo {
    ​
      def main(args: Array[String]): Unit = {
    ​
        // 案例:输入一个数字n,获取1~n的平方形式
        // 例如输入数字4,获取1,4,9,16
    ​
        val n = StdIn.readInt()
    ​
        // 方式一
        val v = new util.ArrayList[Int]()
        for (i <- 1 to n) {
          // v.add(i * i)
          v add i * i
        }
        println(v)
        println("=" * 50)
    ​
        // 方式二
        val square = for (i <- 1 to n) yield i * i
        println(square)
    ​
      }
    ​
    }
  40. 在Scala中,没有breakcontinue关键字

  41. 对于continue而言,Scala就认为可以通过条件判断来实现相同的效果,因此没有必要添加continue关键字来增加学习成本

  42. 中止循环

    1. 通过抛出异常的方式来中止循环

      package com.fesco.loop
      ​
      import scala.io.StdIn
      ​
      object BreakDemo {
      ​
        def main(args: Array[String]): Unit = {
      ​
          val n = StdIn.readInt();
      ​
          for (i <- 1 to n) {
            if (i % 4 == 0)
              throw new RuntimeException()
            println(i)
          }
      ​
        }
      ​
      }

      这种方式确实可以中止循环,但是同时也把程序给结束掉了

    2. 抛出异常,结合try-catch来捕获异常

      package com.fesco.loop
      ​
      import scala.io.StdIn
      ​
      object BreakDemo2 {
      ​
        def main(args: Array[String]): Unit = {
      ​
          val n = StdIn.readInt()
          try {
            for (i <- 1 to n) {
              if (i % 5 == 0)
                throw new RuntimeException()
              println(i)
            }
          } catch {
            case e: RuntimeException => // 捕获到异常之后不做任何处理
          }
      ​
          println("testing")
      ​
        }
      ​
      }
    3. 抛异常这种方式,确实可以结束循环,但是代码的可读性不高,因此Scala中提供了Breaks类,Breaks类中提供了break函数来结束循环

      package com.fesco.loop
      ​
      import scala.io.StdIn
      import scala.util.control.Breaks
      ​
      object BreakDemo3 {
      ​
        def main(args: Array[String]): Unit = {
      ​
          val n = StdIn.readInt()
      ​
          
          for (i <- 1 to n) {
            if (i % 5 == 0) {
              // 本质上还是通过抛出异常的方式来中止循环
              Breaks.break()
            }
            println(i)
          }
      ​
      ​
          println("testing")
      ​
        }
      ​
      }

      为了让代码结构变得比较优雅,在导包的时候可以导入Breaks的所有函数

      package com.fesco.loop
      ​
      import scala.io.StdIn
      // 在Scala中,导包的时候,_表示通配符
      import scala.util.control.Breaks._
      ​
      object BreakDemo4 {
      ​
        def main(args: Array[String]): Unit = {
      ​
          val n = StdIn.readInt()
      ​
          for (i <- 1 to n) {
            // if (i % 6 == 0) break()
            // 调用了break函数,并且函数没有参数,所以()可以省略
            if (i % 6 == 0) break
      ​
            println(i)
          }
          
          println("testing")
      ​
        }
      ​
      }
    案例:数字炸弹
    package com.fesco.loop
    ​
    import scala.io.StdIn
    ​
    object LoopCaseDemo {
    ​
      def main(args: Array[String]): Unit = {
    ​
        // 产生0-100之间的随机数,然后进行猜测
        // 提示猜测范围,如果猜测准确,则爆炸!
        val n = (Math.random() * 101).toInt
        // 定义变量来记录范围
        var min = 0
        var max = 100
        // 提示用户输入
        println(s"请输入 $min~$max 范围内的数字:")
        var x = StdIn.readInt()
        // 判断值是否相等
        while (x != n) {
    ​
          // 判断输入的x是否在指定范围内
          if (x < min || x > max) println("输入的数字不在范围内!,请重新输入")
          else if (x > n) max = x
          else min = x
    ​
          // 重新获取数据
          println(s"请输入 $min~$max 范围内的数字:")
          x = StdIn.readInt()
    ​
        }
    ​
        // 只要循环结束,就表示猜中了
        println("boom!!!")
    ​
      }
    ​
    }
    • Scala也支持do-while结构,语法和Java一样

      do {
          代码块
      } while (条件)
  • 24
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BigData-缑溪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值