Scala

应用

  1. // 退出
  2. sys.exit()

一、基础

1. 数据类型对象 (没有原始类型)

数据类型 描述
Byte 8位有符号值。范围从-128到127
Short 16位有符号值。范围从-32768至32767
Int 32 位有符号值。范围从 -2147483648 to 2147483647
BigInt
Long 64位有符号值。 从-9223372036854775808到9223372036854775807
Float 32位IEEE754单精度浮点数
Double 64位IEEE754双精度浮点数
Char 16位无符号Unicode字符。范围由U+0000至U+FFFF
String 字符序列
Boolean 无论是字面true或false字面
Unit 对应于没有值
Null 空或空引用
Nothing 每一个其他类型的子类型; 包括无值
Any Any类型的超类型;任何对象是任何类型
AnyRef 任何引用类型的超类型

2. 定义变量

  • val 定义不可变的常量

  • var 定义可变的变量

  • 如果定义变量不指定类型,则 Scala 会使用 类型推断(Type Inference),编译器会根据上下文推断出类型信息

  1. 1. val 定义不可变的常量
  2. val test1 = 123
  3. 2. var 定义可变的变量
  4. var test2 = 456
  5. 3. 指定类型
  6. val test3 : String = null
  7. val test4 : Any = "Hellow"
  8. 4. 多个值声明
  9. val xmax,ymax = 100
  10. 5. 多个值指定类型声明
  11. var greeting,message : String = null
  12. 6. 指定类型批量定义,并且复制(val)
  13. val (myInt1: Int, myString1: String) = Pair(40, "Foo")
  14. val (a,b) = (100,200) // 把二元组里的值分别赋给a,b两个变量
  15. 7. lazy 懒值,在调用时才初始化
  16. lazy val words: String = "Hello World"
  17. lazy val fn = (x:Int) => x + 2

2. 数据类型

  • 7 种数据类型 (Byte,Char,Short,Int,Long,Float,Double)
  1. 1. Scala 不刻意区分基本类型和引用类型
  2. 1.toString() // 转化成字符串
  3. 2. Int 1 首先被转换成 RichInt,然后用 to 方法
  4. 1.to(10) // 产出 Range(1,2,3,4,5,6,7,8,10)
  5. 3. Scala 用底层的 java.lang.String 类来表示字符串,通过 StringOps 类给字符串追加了上百种操作方法
  6. "Hello".intersect("World")
  7. 4. 正则匹配
  8. "1111".matches("[0-9]+")

3. apply 方法

  • () 操作符的重载形式,背后实现是 apply() 方法
  1. 1. 案例一
  2. "Hello"(4)
  3. "Hello".apply(4)
  4. 2. 案例二
  5. BigInt("1234567890") // BigInt 的伴生对象
  6. BigInt.apply("1234567890") // 伴生对象
  7. 3. 案例三
  8. Array(1,4,9,16) // Array 的伴生对象
  9. Array.apply(1,4,9,16)

三、控制结构

1. 条件表达式

  • 表达式有值 : 并且每个表达式都有一个输出类型
  • 语句 : 是执行动作
  1. val x = 10
  2. 1. 把表达式返回的类型值,赋值给 s
  3. val s = if (x > 0) 1 else -1
  4. 2. (): 当做 "无有用值的占位符"
  5. if (x < 0) 1 else ()
  6. 3. Unit 类: 当做 Java 中的 void
  7. if (x < 0) 1 else Unit

2. {} 块表达式

  • 块包含一系列的表达式
  • 块最后一个表达式的值,就是块的值
  1. val ds = {
  2. // 赋值动作,本身没有值,严格来说是 Unit 类型,这个类型的值写作 ()
  3. val dx = 1 + 1
  4. dx + 1
  5. }

3. println 输入和输出

  1. 1. 输出
  2. print("Hello World")
  3. 2. 带换行符
  4. println("Hello World")
  5. 3. 格式化字符串
  6. printf("Hello , %s! You ar %d years old\n","Jason",24)

4. readLine 从控制台读取数据

  1. 1. 读取输入行的数据
  2. val name = readLine("Your Name:")
  3. println(name)
  4. 2. 读取 Int
  5. val age = readInt()
  6. println(age)

5. 循环控制

  1. * 循环
  2. 1. do while
  3. var a = 10;
  4. do {
  5. println( "Value of a: " + a );
  6. a += 1;
  7. } while ( a < 20 )
  8. 2. while
  9. var a = 0
  10. while( true ){
  11. println( "Value of a: " + a );
  12. a += 1
  13. }
  14. 3. for
  15. var a = 0;
  16. // for 循环范围, 左箭头 < - 操作者被称为生成器
  17. for( a <- 2 to 10){
  18. println( "Value of a: " + a );
  19. }
  20. 4. for 循环执行的集合
  21. var a = 0;
  22. val numList = List(1,2,3,4,5,6);
  23. for( a <- numList ){
  24. println( "Value of a: " + a );
  25. }
  26. 5. for 循环字符串
  27. for (i <- "Hello")
  28. println(i)
  29. 6. 高阶应用,多个生成器
  30. // (循环一次 i <- 1 to 3; 再循环一次 j <- 1 to 3) 以此类推
  31. for (i <- 1 to 3; j <- 1 to 3) {
  32. println("i=" + i + " j=" + j)
  33. }
  34. // 笛卡尔集
  35. i=1 j=1
  36. i=1 j=2
  37. i=1 j=3
  38. i=2 j=1
  39. i=2 j=2
  40. i=2 j=3
  41. i=3 j=1
  42. i=3 j=2
  43. i=3 j=3
  44. 7. for 生成器守卫
  45. for (i <- 1 to 3;
  46. // 生成器守卫
  47. j <- 1 to 3 if i != j)
  48. {
  49. println("i=" + i + " j=" + j)
  50. }
  51. // 过滤后的结果
  52. // i=1 j=1 这行被过滤
  53. i=1 j=2
  54. i=1 j=3
  55. i=2 j=1
  56. //i=2 j=2 这行被过滤
  57. i=2 j=3
  58. i=3 j=1
  59. i=3 j=2
  60. //i=3 j=3 这行被过滤
  61. 8. 变量 for 循环
  62. for (i <- 1 to 3;
  63. from = 4 - i;
  64. j <- from to 3)
  65. {
  66. println("i=" + i + " j=" + j)
  67. }
  68. 9. for yield 会根据表达式构造一个新的集合
  69. var retVal = for {
  70. a <- List(1,2,3,4,5,6,7,8,9,10)
  71. if a != 3
  72. if a < 8
  73. } yield a
  74. println(retVal)
  75. //List(1, 2, 4, 5, 6, 7)
  76. 10. for yield 会根据表达式构造一个新的集合
  77. val a = for(i <- 1 to 10) yield i + 1
  78. println(a)
  79. //Vector(2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
  80. * 循环控制
  81. 1. 导入包
  82. import scala.util.control._
  83. 2. 创建对象
  84. val outer = new Breaks;
  85. 3. 包裹循环体
  86. outer.breakable {
  87. for( a <- 2 to 10){
  88. if (a > 9) {
  89. // 结束循环, Scala 没有 continue(如果需要,请自行控制循环的范围)
  90. outer.break;
  91. }
  92. println( "Value of a: " + a );
  93. }
  94. }

四、函数与异常

  • 函数在 Scala 中属于一级对象,可以作为参数传递给其他函数,可以作为另一个函数的返回值,或者赋给一个变量

  • 关键字 def 函数名称 (参数名称 : 类型) : 返回类型 = 函数体

    • 1) 如果不是递归函数可以选择省略 : 返回类型
    • 2) 支持定义匿名函数,匿名函数由参数列表,箭头连接符和函数体组成
    • 3) 不带参数的 Scala 方法,通常不适用圆括号
    • 4) 过程函数: 不返回任何值,即 Unit 类型,所以可以不需要 = 号
    • 5) 函数不是递归,无需指定返回类型
  • Scala 没有静态方法,有类似特性叫做单列对象 (singleton object)

  • Scala 类会有个伴生对象 (companion object)

1. 函数与表达式

  1. 1. scala 开头的包,可以省去 scala 前缀
  2. // import scala.math._ = import math._
  3. // math.sqrt(2) = scala.math.sqrt(2)
  4. import scala.math._
  5. math.sqrt(2);
  6. 2. 定义函数
  7. 1) 函数不是递归,无需指定返回类型
  8. // 方式一
  9. def abs (x: Double) = if (x >= 0) x else -x
  10. // 方式二
  11. def abs (n: Int) = {
  12. if (n >= 0) n else -n
  13. }
  14. 2) 定义函数,函数是递归的,需要指定返回类型
  15. // 方式一
  16. def fac (n: Double): Double = if (n <= 0) 1 else n * fac(n-1)
  17. // 方式二
  18. def fac (n: Int): Int = {
  19. if (n <= 0) {
  20. 1
  21. } else {
  22. n * fac(n-1)
  23. }
  24. }
  25. 3. 定义函数: 带名参数
  26. def decorate(str: String, left: String = "(", right: String = ")" ) = {
  27. left + str + right
  28. }
  29. // 使用
  30. decorate("Hello",right = "zzz")
  31. 4. 定义函数: 变长参数
  32. def sum(args: Int*) = {
  33. var result = 0
  34. for (arg <- args) result += arg
  35. result
  36. }
  37. // 直接使用
  38. sum(1,2,3,4,5)
  39. // 传入序列: 需要使用 :_* 操作
  40. // :_* 当做参数序列处理,追加 :_*
  41. sum(1 to 5:_*) // 1 to 5 被当做参数序列处理
  42. 5. 定义函数: 过程函数
  43. 过程函数不返回任何值,即 Unit 类型,所以可以不需要 =
  44. // 案例一
  45. def box(s: String) {
  46. }
  47. // 案例二,推荐写法
  48. def box(s: String): Unit = {
  49. }
  50. 6. 异常处理
  51. // try/catch
  52. try {
  53. } catch {
  54. case ex: Exception =>
  55. case _:
  56. }
  57. // try/finally
  58. try {
  59. } finally {
  60. }

2. 高阶函数

  1. 1. Scala 函数按名称调用 : (方法体中,使用时再执行的函数)
  2. object Test {
  3. def main(args: Array[String]) {
  4. // 调用了
  5. delayed(time());
  6. }
  7. // 默认最后一行作为返回
  8. def time() = {
  9. println("time(): 开始执行了...")
  10. System.nanoTime
  11. }
  12. // 表达式调用时,才运行 time() 函数,并且获得返回值
  13. // 注意表达式 ( t: => Long )
  14. def delayed( t: => Long ) = {
  15. println("delayed(): 开始执行了...")
  16. // 这里才开始调动 time() 方法
  17. println("调用时,运行 time() 返回值: " + t)
  18. }
  19. }
  20. 2. Scala 高阶函数和函数传递
  21. // 案例 1
  22. object Test {
  23. // 等待入参的函数
  24. def layout[A] (x: A) : String = {
  25. return x.toString()
  26. }
  27. // fn1: Int => String 是一个函数,入参是 Int,返回 String
  28. // v2: Int 是一个入参
  29. // fn1(v2) 是一个匿名函数
  30. def apply(fn1: Int => String, v2: Int) = {
  31. fn1(v2)
  32. }
  33. def main(args: Array[String]) {
  34. // 把 layout 函数 和 10 ,传递给 apply(fn1,v2)
  35. // 执行 fn1(v2) ,就是相当于执行 layout(10)
  36. var rs = apply( layout, 10)
  37. println(rs)
  38. }
  39. }
  40. // 案例 2
  41. // 功能函数写法
  42. def featureFn(arg1: Int, arg2: Int) {
  43. println(arg1 + arg2)
  44. }
  45. // 执行函数写法
  46. // fn: (String, String) 表示一个函数参数, featureFn 传递给 runFn 执行, 其中参数类型保持一致即可
  47. def runFn(fn: (Int, Int) => Unit) {
  48. fn(1, 2)
  49. }
  50. // 调用执行
  51. runFn(featureFn)
  52. 3. Scala 匿名函数 (快速定义一个函数)
  53. (参数) => {方法体} // => 把参数和方法体分开
  54. // 函数名 = (入参) => 函数体
  55. var fn1 = (x:Int) => x + 2
  56. // 多参数匿名函数
  57. var fn2 = (x:Int,y:Int) => x + y
  58. // 无参数函数
  59. var fn3 = () => {
  60. System.getProperty("user.dir")
  61. }
  62. // 或者这样
  63. { i: Int =>
  64. println("Hello World")
  65. i * 2
  66. }
  67. 4. Scala 柯里函数 (柯里转换函数接受多个参数成一条链的函数,每次取一个参数。也可以定义多个参数列表)
  68. object Test {
  69. /*
  70. * 写法 1
  71. * def fn1 ()() = {}
  72. */
  73. def fn1 (s1:String) (s2:String) = {
  74. s1 + s2
  75. }
  76. /*
  77. * 写法 2
  78. * def fn2 () = () => {}
  79. */
  80. def fn2 (s1:String,s2:String) = (s3:String) => {
  81. s1 + s2 + s3
  82. }
  83. def main(args: Array[String]) {
  84. var str1 : String = "Hello,"
  85. var str2 : String = "World,"
  86. var str3 : String = "Scala!"
  87. println(fn1(str1)(str2))
  88. println(fn2(str1,str2)(str3))
  89. }
  90. }
  91. 5. Scala 嵌套函数 (局部被调用)
  92. object Test {
  93. def main(args: Array[String]) {
  94. var rs = this.fn1(2)
  95. println(rs)
  96. }
  97. def fn1 (i : Int) : Int = {
  98. // 定义嵌套函数
  99. def fn2 (x : Int,y : Int) : Int = {
  100. x + y
  101. }
  102. // 局部被调用
  103. fn2(i,1)
  104. }
  105. }
  106. 6. Scala 部分应用函数 (当被调用的时候才初始化)
  107. import java.util.Date;
  108. object Test {
  109. def main(args: Array[String]) {
  110. // 创建时间对象
  111. val date = new Date;
  112. // 创建应用函数, 把 date 绑定在第一个参数(这个点记录的函数), 并且在(下划线)处绑定第二个参数
  113. val fn2 = fn1(date, _: String)
  114. fn2("message1")
  115. fn2("message2")
  116. fn2("message3")
  117. }
  118. def fn1(date: Date, message: String) = {
  119. println(date + "------" + message)
  120. }
  121. }
  122. 7. Scala 函数重写
  123. // 原始类
  124. object ScalaIntList {
  125. final case class Node(next: Node, value: Int)
  126. }
  127. // 重写前
  128. final class ScalaIntList {
  129. var head: ScalaIntList.Node = null
  130. var size: Int = 0
  131. }
  132. // 改写(通过语言特性)
  133. object ScalaIntList {
  134. final case class Node(next: Node, value: Int)
  135. }
  136. // 后
  137. final class ScalaIntList {
  138. var head: ScalaIntList.Node = null
  139. final def size: Int = {
  140. var n = head
  141. var i = 0
  142. while (n != null) {
  143. n = n.next
  144. i++
  145. }
  146. i;
  147. }
  148. }
  149. // 访问
  150. val myList = new ScalaIntList
  151. println(myList.size);
  1. ### `3. 闭包函数`
  2. - 闭包是也是函数,它的返回值取决于此函数之外声明一个或多个变量的值
  3. ``` java
  4. object Test {
  5. def main(args: Array[String]) {
  6. var rs = fn(2)
  7. println(rs)
  8. }
  9. var factor : Int = 3
  10. // 定义闭包函数,外部不调用的时候,形成闭包
  11. val fn = (i:Int) => {
  12. // i 是入参
  13. // factor 是外部环境的变量
  14. i * factor
  15. }
  16. }

五、数组

1. 定义数组

  1. 1. 定义固定长度数组
  2. import Array._;
  3. // 存放 10 个元素,初始化值为 null
  4. val arr = new Array[Int](10);
  5. var arr : Array[Int] = new Array[Int](10)
  6. // 定义数组, Array[String] 这是根据推断机制推断出来的
  7. val s = Array("Hello","A")
  8. val s: Array[String] = Array("Hello","A")
  9. // 访问数组
  10. s.(0)
  11. // 验证值是否在数组中
  12. s.contains("A")
  13. 2. 变长数组: 数组缓冲(ArrayBuffer) 不定长数组
  14. import scala.collection.mutable.ArrayBuffer;
  15. // 定义缓冲数组
  16. val inventoryIds: ArrayBuffer[String] = new ArrayBuffer[String]()
  17. b += 1 // 在数组尾部追加元素
  18. b += (1,2,3,4) // 数组尾部追加多个元素,用括号括起来
  19. b ++= Array(5,6,7) // 追加任何集合
  20. b.trimEnd(1) // 移除最后 1 个元素
  21. b.insert(2,8,9) // 在下标 2 之前插入 8、9 这两个元素
  22. b.remove(2) // 移除指定下标的元素
  23. b.remove(2,3) // 移除指定下标后的的 3 个元素
  24. // 把 ArrayBuffer 转换成一个 Array
  25. b.toArray
  26. // 把 Array 转换成一个 ArrayBuffer
  27. b.toBuffer
  28. 3. 定义数组: 多维数组
  29. 1) Array[Array[Double]](n) // 数组指定长度
  30. val arr = Array.ofDim[Double](3,4)
  31. arr(1)(2) = 123 // 赋值
  32. print(arr(1)(2)) // 访问
  33. 2) new Array[Array[Int]](10)
  34. val arr = new Array[Array[Int]](10)
  35. for (i <- 0 until arr.length)
  36. arr(i) = new Array[Int](2)
  37. println(arr(2).toBuffer)
  38. 4. 遍历数组
  39. * until : RichInt 类的方法,返回所有小于(但不包含)上限的数字
  40. val a = (0 until 10) // 实际调用的是 0.until(10)
  41. println(a) // Range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
  42. 1) 按照顺序遍历
  43. for (i <- 0 until b.length)
  44. println(b(i))
  45. 2) 按照顺序遍历 : 步长 2
  46. 0 until (b.length,2) = 0.until(b.length,2)
  47. for (i <- 0 until (b.length,2))
  48. println(b(i))
  49. 3) 倒着循环
  50. (0 until b.length).reverse = 0.until(b.length).reverse
  51. for (i <- (0 until b.length).reverse)
  52. println(b(i))
  53. 5. 数组转换
  54. var a = Array(2,3,5,7,11)
  55. // 案例一
  56. val result = for(
  57. elem <- a
  58. if elem > 3 // 满足条件的值拿出来
  59. ) yield {
  60. 1 + elem
  61. }
  62. // 案例二, 保留条件通过后的的数据
  63. val result = a.filter { _ > 3 }.map( 1 + _ ) // 作用相同
  64. // 输出
  65. println(result.toBuffer) // ArrayBuffer(6, 8, 12)
  66. println(result.mkString(",")) // 把数组的值,按照指定符号分割
  67. * 数组方法
  68. 1) concat() 组合数组
  69. var concatArr = concat(arr1,arr2,arr3)
  70. 2) range() 生成返范围数组
  71. // 生成 10 ~ 20 的数组
  72. var myList2 = range(10,20)
  73. // 生成 10 ~ 20 的数组, 步长设置为 2
  74. var myList1 = range(10, 20, 2)

2. 映射和元祖 (key/value 对)

  1. 1. 定义 Map: 不可变
  2. import scala.collection.immutable.Map;
  3. import scala.collection.immutable.HashMap;
  4. // 三种定义 空值 Map 写法
  5. val map = Map()
  6. val map : Map[String,Int] = Map()
  7. val map : Map[String,Int] = Map[String,Int]()
  8. // 三种定义 默认值 Map 写法
  9. val map = Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8) // 自动判断定义
  10. val map = Map(("Alice", 10), ("Bob", 3), ("Cindy", 8)) // 元祖类型
  11. val map: Map[String, Int] = Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8) // 指定类型定义
  12. println(map.toBuffer) // 打印
  13. 2. 定义 Map: 可变的
  14. // 定义一个空的可变的 Map 的两种写法
  15. import scala.collection.mutable.Map
  16. import scala.collection.mutable.HashMap
  17. var map = new HashMap[String,Int];
  18. var map : Map[String,Int] = new HashMap[String,Int]();
  19. 3. 操作 Map
  20. var map: Map[String, Int] = Map[String, Int]()
  21. map += ("a" -> 1, "b" -> 2) // 增加键值对
  22. map.put("c", 3) // 增加键值对
  23. map("a") = 2 // 更新 key 值
  24. map -= "b" // 移除 key
  25. map.remove("b") // 移除 key
  26. map.contains("a") // 验证 key 是否存在
  27. map("a") // 读取 key
  28. map.getOrElse("a", 0) // 当 key 不出在,返回默认值
  29. map.get("a") // 返回一个 Option 对象 Some(值) 或者 None
  30. map.toMap // 可变 map 转换成为不可变 Map
  31. // 不可变 Map 转换为可变 Map
  32. scala.collection.mutable.Map(map.toSeq:_*) // 方法一
  33. scala.collection.mutable.Map[String, Object](map.toSeq:_*)
  34. collection.mutable.Map() ++ map // 方法二
  35. 实际案例: 把不可变 Map 转换为 可变 Map
  36. val bsMap = Map[String, Object]() // 这里的 Object 里面包含的也是一个 Map
  37. val bsMapFormat = bsMap.map{case (k,v) =>
  38. val curK = k
  39. // 把元祖 v 转换为 Map[String,String]
  40. val curV = v.asInstanceOf[scala.collection.immutable.Map[String,String]]
  41. // 再把 map 转换为可变 Map
  42. val formatV = scala.collection.mutable.Map(curV.toSeq:_*)
  43. k -> formatV
  44. }
  45. 4. for 迭代映射 Map
  46. // for ((k, v) <- 映射) 处理 k 和 v
  47. for ((k, v) <- map) {
  48. println("k:" + k + " v:" + v)
  49. }
  50. // 只读 key
  51. for (k <- map.keySet) {
  52. println(k)
  53. }
  54. val tmp = map.keySet.toArray
  55. tmp(0)
  56. // 只读 value
  57. for (v <- map.values) {
  58. println(v)
  59. }
  60. 5. 元祖 tuple
  61. 1) 定义元祖
  62. val t = (1, 3.14, "Fred")
  63. val t: (Int,Double,String) = (1, 3.14, "Fred")
  64. val t: (Int,Double,String) = null
  65. 2) 元祖复制
  66. val (a, b, c) = t
  67. println(c) // Fred
  68. //元祖复制,只要部分 (使用 _ 占位符来代替)
  69. val (a, _, c) = t
  70. println(c) // Fred
  71. 3) 拉链操作: 合并元祖
  72. val t1 = Array("a", "b", "c")
  73. val t2 = Array(1, 2, 3)
  74. val rs = t1.zip(t2) // 转换成对偶数组
  75. println(rs.toBuffer) // ArrayBuffer((a,1), (b,2), (c,3))
  76. val maps = rs.toMap // 转换成 Map
  77. println(maps) // Map(a -> 1, b -> 2, c -> 3)
  78. 4) 访问元祖
  79. t._1
  80. t._2
  81. 5) 定义返回 元祖的函数
  82. // 拆解 Map 返回
  83. def dismantlingMap (data: Map[Int,Int]): (Int, Int) = {
  84. val keys = data.keySet.toArray
  85. (keys(0), data.get(keys(0)).get)
  86. }

3. 集合

  1. 1) List[T] 集合
  2. Nil 表示 LIST
  3. (1) List of Strings
  4. val fruit: List[String] = List("apples", "oranges", "pears")
  5. // 另一种写法
  6. val fruit = "apples" :: ("oranges" :: ("pears" :: Nil)
  7. (2) List of Intege
  8. val nums: List[Int] = List(1, 2, 3, 4)
  9. // 另一种写法
  10. val nums = 1 :: (2 :: (3 :: (4 :: Nil)))
  11. (3) Empty List
  12. val empty: List[Nothing] = List()
  13. // 另一种写法
  14. val empty = Nil
  15. (4) 二维 List
  16. val dim: List[List[Int]] =
  17. List(
  18. List(1, 0, 0),
  19. List(0, 1, 0),
  20. List(0, 0, 1)
  21. )
  22. // 另一种写法
  23. val dim = (1 :: (0 :: (0 :: Nil))) ::
  24. (0 :: (1 :: (0 :: Nil))) ::
  25. (0 :: (0 :: (1 :: Nil))) :: Nil
  26. (5) 可变的 List
  27. import scala.collection.mutable.ListBuffer
  28. val list = ListBuffer[Any]()
  29. list.append(1)
  30. (6) 循环累加
  31. var list = List[String]()
  32. for(i <- 0 to jsonArr.size() - 1) {
  33. // 在List的头部增加元素
  34. val node = jsonArr.get(i).toString()
  35. // list 头部放入节点
  36. list = list +: list
  37. // list 追加节点
  38. list = list :+ node
  39. }
  40. 2) Set 集合是不包含重复元素的集合
  41. // 默认使用的是不可变集合
  42. import scala.collection.immutable.Set;
  43. // 可变集合
  44. import scala.collection.mutable.Set;
  45. (1) Empty set of integer type
  46. var s : Set[Int] = Set()
  47. (2) Set of integer type
  48. var s : Set[Int] = Set(1,3,5,7)
  49. // 另一种写法
  50. var s = Set(1,3,5,7)
  51. 3) Map 映射是键/值对的集合
  52. import scala.collection.mutable.Map;
  53. (1) 定义 Map , 设置值
  54. var map1 : Map[Char,Int] = Map()
  55. map1 += ('a' -> 1 )
  56. map1 += ('b' -> 2 )
  57. (2) 定义 Map , 设置默认值
  58. val map2 = Map("red" -> "#FF0000", "azure" -> "#F0FFFF")
  59. (3) 操作
  60. map1.contains('keyName') // 验证 key 是否存在
  61. 4) Tuples 元组可以容纳不同类型的对象,但它们也是不可改变的
  62. (1) 定义 4 位的元祖
  63. 语法 :
  64. new Tuple[n]
  65. 例如 :
  66. val t = new Tuple4(1, "hello", "World","Scala")
  67. (2) 直接定义元祖
  68. val t = (1, "hello", "World","Scala")
  69. (3) 访问
  70. t._1
  71. t._2
  72. t._3
  73. 5) Option[T] 可以是一些[T]或 None 对象,它代表一个缺失值
  74. // 定义变量 a ,类型为 Option[Int]
  75. val a : Option[Int] = Some(5)
  76. var rs = a.getOrElse(0)
  77. val b : Option[Int] = None
  78. var rs = b.getOrElse(10)
  79. 6) Iterators 迭代器不是集合,而是一种由一个访问的集合之一的元素。
  80. //在一个迭代的两种基本操作:next 和 hasNext。
  81. val it = Iterator("a", "number", "of", "words")
  82. while (it.hasNext){
  83. // it.next()将返回迭代器的下一个元素,推进迭代器的状态
  84. println(it.next())
  85. }
  86. *) 排序
  87. 1. map 排序
  88. val mapData:MAP[String, String] = Map("90" -> "1", "87" -> "2")
  89. mapData.toList.sortBy(kv =>
  90. kv._2.toString().toInt
  91. ).reverse. // 表示倒序,如果不写则是正序
  92. foreach {
  93. case (key,value) => println(key + " = " + value)
  94. }
  95. // 或者再次转换成
  96. mapData.toList.sortBy(kv => kv._2.toString().toInt).reverse.toMap

六、类与对象

1. Class 类

  1. 1. 对象方法说明
  2. class Counter {
  3. var value = 0 // 必须提前初始化
  4. private var value2 = 0 // 测试方法 2
  5. def increment() { value += 1} // 方法默认是公有的
  6. def current() = value; // 返回值 value
  7. }
  8. // 调用
  9. val myCounter = new Counter() // 或者 new Counter
  10. myCounter.increment()
  11. // 调用无参数方法,可以不写 ()
  12. myCounter.current
  13. myCounter.current()
  14. // 对于有修改的方法使用 ()
  15. myCounter.increment()
  16. // 只读取值,不修改对象状态的方法,不带是不错的风格 ()
  17. myCounter.current
  18. 2. getter setter
  19. /**
  20. * getter 和 setter
  21. * 1. 如果字段是私有的 : getter 和 setter 方法也是私有的
  22. * 2. 如果字段是 val : 只生成 getter, 修改无效
  23. * 3. 不需要 getter 和 setter : 将字段声明为 private[this]
  24. */
  25. class GetterAndSetter {
  26. var age = 0
  27. private var value = 0 // 私有变量,
  28. def increment() { value += 1}
  29. def current = value; // 声明没有 (), 因为 getter 方法没有定义 (), 只读取值的方法不需要写 ()
  30. // 对象私有,只能访问到当前对象的 value 字段
  31. def isLess(other: GetterAndSetter) = {
  32. value < other.value
  33. value
  34. }
  35. }
  36. var getterAndSetter = new GetterAndSetter()
  37. getterAndSetter.age // 调用 age() 方法, 在 JVM 中 public int age()
  38. getterAndSetter.age = 21 // 调用 this.age = (21), 在 JVM 中 public void age_$eq(int)
  39. getterAndSetter.increment() // 修改值
  40. getterAndSetter.current // 直接访问, 这样调用就出错了 getterAndSetter.current()
  41. println(getterAndSetter.isLess(getterAndSetter)) //
  42. 3. 主构造器(primary constructor) 辅助构造器(auxiliary constructor)
  43. 1) 辅助构造器
  44. class Person {
  45. private var name = ""
  46. private var age = 0;
  47. def this(name: String) { // 一个辅助构造器 this
  48. this() // 调用构造器
  49. this.name = name
  50. }
  51. def this(name: String, age: Int) { // 又一个辅助构造器
  52. this(name) // 调用辅助构造器
  53. this.age = age
  54. }
  55. }
  56. val p1 = new Person // 主构造器
  57. val p2 = new Person("A") // 第一个辅助构造器
  58. val p3 = new Person("B",1) // 第二个辅助构造器
  59. 2) 主构造器
  60. class Person(name: String, age: Int) {
  61. def printLn() : Unit = {
  62. println(this.name)
  63. println(this.age)
  64. }
  65. }
  66. val p1 = new Person("Jason",24) // 主构造器
  67. p1.printLn()

2. Object 对象

  • object 中所有成员变量和方法默认都是 static
  • object 使用场景
    • 存放工具函数
    • 存放常量、静态方法
    • 对象单例、高效共享不可变实例
  • class 可以拥有一个同名的伴生对象 object
  • object 的 apply 方法通常用来构造伴生类 class 的新实例
  • 可以通过扩展 Enumeration 对象实现枚举
  1. 1. 单例对象
  2. object Accounts {
  3. private var lastNumber = 0
  4. def newUniqueNumber() = {
  5. lastNumber += 1
  6. lastNumber
  7. }
  8. }
  9. Accounts.newUniqueNumber()
  10. 2. 伴生对象
  11. class Account {
  12. val id = Account.newUniqueNumber() // 静态方法
  13. private var balance = 0.0
  14. def deposit(amount: Double) {balance += amount}
  15. }
  16. // class Account 的伴生对象
  17. object Account {
  18. // 类和伴生对象可以相互访问私有特性,但必须在同一个文件中
  19. private var lastNumber = 0
  20. private def newUniqueNumber() = {
  21. lastNumber += 1
  22. lastNumber
  23. }
  24. }
  25. 4. apply 伴生方法
  26. // 相当调用 Array.apply()
  27. Array("a","b","c") // 相当于 Array.apply("a","b","c")
  28. // 这是调用构造器 this()
  29. new Array("a","b","c")
  30. // 案例
  31. class Account private(val id: Int, user: String) {
  32. private var people = user;
  33. }
  34. // 伴生对象
  35. object Account {
  36. // 自定义 apply 方法
  37. def apply(user: String) = {
  38. new Account(1,user)
  39. }
  40. }
  41. // 调用
  42. Account("angejia") // 案例一
  43. Account.apply("angejia") // 案例二
  44. 5. 应用程序 App
  45. // 第一种写法
  46. object Hello extends App {
  47. println(args.length)
  48. println(args(0))
  49. }
  50. // 第二种
  51. object Hello {
  52. def main(args: Array[String]) {
  53. }
  54. }

3. 继承

  • extends 继承父类

  • override 重写方法

  • final

    • java 表示不可变
    • scala 表示不可重写
  • super 调用超类

  1. 1. 继承 + 抽象类
  2. abstract class Person {
  3. def getId(id: Int): Int // 定义抽象方法
  4. def getName(name: String): String;
  5. // 无参数方法
  6. def getAge : Int
  7. }
  8. class PersonImpl extends Person{
  9. // 实现抽象方法
  10. def getId(id: Int): Int = {
  11. 1
  12. }
  13. // 实现抽象方法
  14. def getName(name: String): String = {
  15. "Angejia"
  16. }
  17. // 实现无参数方法
  18. def getAge : Int = 1
  19. }
  20. // 调用
  21. val person: Person = new PersonImpl
  22. person.getId(1)

4. 特性 - 类似接口

  • abstract 抽象类, 接口, 可实现部分方法
  • trait 特性类, 可实现部分方法
  • with Class 实现或继承接口类后, with 可继承多个特性
  1. trait Equal {
  2. def isEqual(x: Any): Boolean
  3. def isNotEqual(x: Any): Boolean = !isEqual(x)
  4. }
  5. // 定义接口类 某种动物
  6. abstract class Animal {
  7. // 定义未实现的方法
  8. def walk(speed:Int)
  9. // 接口可以实现方法
  10. def breathe() = {
  11. println("animal breathes")
  12. }
  13. }
  14. // 定义特性类 飞行
  15. trait Flyable {
  16. def hasFeather = true
  17. def fly
  18. }
  19. // 定义特性类 游泳
  20. trait Swimable {
  21. def swim
  22. }
  23. // 定义一个实体类(一种鸟) extends 动物 with 可以飞行 with 可以游泳
  24. class FishEagle extends Animal with Flyable with Swimable {
  25. // 实现具体方法
  26. def walk(speed:Int) = println("fish eagle walk with speed " + speed)
  27. def swim() = println("fish eagle swim fast")
  28. def fly() = println("fish eagle fly fast")
  29. }
  30. // 运行
  31. object App {
  32. def main(args : Array[String]) {
  33. val fishEagle = new FishEagle
  34. val flyable:Flyable = fishEagle
  35. flyable.fly
  36. val swimmer:Swimable = fishEagle
  37. swimmer.swim
  38. }
  39. }

5. 模式匹配

  • 经过函数值和闭包
  1. object Test {
  2. def main(args: Array[String]) {
  3. println(matchTest(3)) // many
  4. }
  5. // 模式匹配, ps : 注意写法 x match
  6. def matchTest(x: Int): String = x match {
  7. case 1 => "one"
  8. case 2 => "two"
  9. case _ => "many"
  10. }
  11. // 第二种写法
  12. def matchTest2(x: Any){
  13. // x 表示变量值
  14. x match {
  15. case 1 => "one"
  16. case "two" => 2
  17. case y: Int => "scala.Int"
  18. case _ => "many"
  19. }
  20. }
  21. }
  22. /**
  23. * 模式匹配类
  24. */
  25. object Test {
  26. // 模式匹配类.
  27. case class Person(name: String, age: Int)
  28. def main(args: Array[String]) {
  29. val alice = new Person("Alice", 25)
  30. val bob = new Person("Bob", 32)
  31. val charlie = new Person("Charlie", 32)
  32. for (person <- List(alice, bob, charlie)) {
  33. // 模式匹配
  34. person match {
  35. case Person("Alice", 25) => println("Hi Alice!")
  36. case Person("Bob", 32) => println("Hi Bob!")
  37. case Person(name, age) =>
  38. println("Age: " + age + " year, name: " + name + "?")
  39. }
  40. }
  41. }
  42. }
  43. // 返回结果
  44. Hi Alice!
  45. Hi Bob!
  46. Age: 32 year, name: Charlie?
  47. /**
  48. * 案例:学校门禁
  49. * Scala 中提供了一种特殊的类,用 case class 进行声明,中文也可以称作样例类。case class 其实有点类似于 Java 中的 JavaBean 的概念。即只定义 field,并且由 Scala 编译时自动提供 getter 和 setter 方法,但是没有 method。
  50. * case class 的主构造函数接收的参数通常不需要使用 var 或 val 修饰,Scala 自动就会使用 val 修饰(但是如果你自己使用 var 修饰,那么还是会按照 var 来)
  51. * Scala 自动为 case class 定义了伴生对象,也就是 object,并且定义了 apply() 方法,该方法接收主构造函数中相同的参数,并返回 case class 对象
  52. */
  53. class Person
  54. case class Teacher(name: String, subject: String) extends Person
  55. case class Student(name: String, classroom: String) extends Person
  56. def judgeIdentify(p: Person) {
  57. p match {
  58. case Teacher(name, subject) => println("Teacher, name is " + name + ", subject is " + subject)
  59. case Student(name, classroom) => println("Student, name is " + name + ", classroom is " + classroom)
  60. case _ => println("Illegal access, please go out of the school!")
  61. }
  62. }
  63. /**
  64. * 案例:成绩查询
  65. * Scala 有一种特殊的类型,叫做 Option。Option 有两种值,一种是 Some,表示有值,一种是 None,表示没有值。
  66. * Option 通常会用于模式匹配中,用于判断某个变量是有值还是没有值,这比 null 来的更加简洁明了
  67. * Option 的用法必须掌握,因为 Spark 源码中大量地使用了 Option,比如 Some(a)、None 这种语法,因此必须看得懂 Option 模式匹配,才能够读懂 spark 源码。
  68. */
  69. val grades = Map("Leo" -> "A", "Jack" -> "B", "Jen" -> "C")
  70. def getGrade(name: String) {
  71. val grade = grades.get(name)
  72. grade match {
  73. case Some(grade) => println("your grade is " + grade)
  74. case None => println("Sorry, your grade information is not in the system")
  75. }
  76. }

* 时间应用

1. sleep

  1. 1. TimeUnit
  2. import java.util.concurrent.TimeUnit
  3. TimeUnit.SECONDS.sleep(4); // 停顿 1 秒
  4. TimeUnit.MINUTES.sleep(4); // 停顿 1 分
  5. TimeUnit.HOURS.sleep(1); // 停顿 1 小时
  6. TimeUnit.DAYS.sleep(1); // 停顿 1 天
  7. 2. Thread
  8. import java.lang.Thread
  9. Thread.sleep(1 * 1000) // 停顿 1 秒
  10. Thread.sleep(60 * 1000) // 停顿 1 分
  11. Thread.sleep(60 * 60 * 1000) // 停顿 1 小时
  12. Thread.sleep(24 * 60 * 60 * 1000) // 停顿 1 天

* 技巧

1. 技巧

  1. 1. 语法
  2. map(_._2) 等价于 map(t => t._2) // t 是个 2 项以上的元组
  3. map(_._2, _) 等价与 map(t => t._2, t)
  4. 2. 变量类型传递(元祖) Tuple2
  5. // spark 抽取前 n 个数据,
  6. val id = inventoryId
  7. val result: Array[(Int, Double)] = itemCosineSimilarity.take(1000)
  8. // 转换成元祖 Tuple2
  9. val t: (Int,Array[(Int, Double)]) = (id, result)
  10. // 在其他位置访问
  11. val inventoryData = t
  12. inventoryData._1
  13. inventoryData._2(0)._1
  14. 3. 类型转换
  15. 1) scala 内部, 类型转换
  16. // 把 Obj 转化弄成 Map[String, String], 这个 Obj 必须是被转换对象的子类
  17. obj.asInstanceOf[collection.Map[String, Object]]
  18. 2java scala
  19. // 自动完成双向转型
  20. import collection.JavaConversions._
  21. // 进而显式调用 asJava() 或 asScala() 方法完成转型
  22. import collection.JavaConverters._
  23. // 例如: 显示 java 对象转换为 scala 对象
  24. Map[String, String].asScala()
  25. 支持转换的数据类型
  26. * scala.collection.Iterable <=> java.lang.Iterable
  27. * scala.collection.Iterable <=> java.util.Collection
  28. * scala.collection.Iterator <=> java.util.{ Iterator, Enumeration }
  29. * scala.collection.mutable.Buffer <=> java.util.List
  30. * scala.collection.mutable.Set <=> java.util.Set
  31. * scala.collection.mutable.Map <=> java.util.{ Map, Dictionary }
  32. * scala.collection.concurrent.Map <=> java.util.concurrent.ConcurrentMap
  33. * scala.collection.Seq => java.util.List
  34. * scala.collection.mutable.Seq => java.util.List
  35. * scala.collection.Set => java.util.Set
  36. * scala.collection.Map => java.util.Map
  37. * java.util.Properties => scala.collection.mutable.Map[String, String]
  38. 4. 读取 resources 目录下的文件
  39. import scala.io.Source
  40. import java.io.{ InputStream, BufferedReader, InputStreamReader, PushbackReader }
  41. // 读取行
  42. val lines = Source.fromURL(getClass.getResource("/xxx.conf")).getLines()
  43. lines.foreach(println)
  44. // 获取 resource 文件读输入流
  45. val inputStreamReader: InputStreamReader = Source.fromURL(getClass.getResource("/xxx.conf")).reader()

2. 修饰符

  1. @volatile 修饰符, 告诉编译器变量是随时可能发生变化的, 每次访问都需要重新读取
  2. @volatile private var sr: String = null

3. 语言特性