欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

study-notes(11 Scala)

程序员文章站 2022-03-04 14:08:33
...

这篇文章是将自己所学技术按模块划分总结而成的笔记,包含了 JavaSE、JavaWeb(SpringMVC、Spring、MyBatis、SpringBoot、SpringCloud 等)、Linux、Hadoop、MapReduce、Hive、Scala、Spark 等,希望通过这些笔记的总结,不仅能让自己对这些技术的掌握更加深刻,同时也希望能帮助一些其他热爱技术的人,这些笔记后续会继续更新,以后自己学习的其他最新技术,也都会以这样笔记的形式来保留,这些笔记已经共享到 Github,大家可以在那里下载到 Markdown 文件,如果大家在看的时候有什么问题或疑问,可以通过邮箱与我取得联系,或者在下面的评论区留言,同时也可以在 Github 上与我进行互动,希望能与大家一起相互学习,相互进步,共同成长。

本篇文章 Github 地址 : https://github.com/wpwbb510582246/study-notes/blob/master/1 JavaSE/1 JavaSE.md

项目 Github 地址 : https://github.com/wpwbb510582246/study-notes

email : [email protected]

博客地址 : https://blog.csdn.net/wpwbb510582246

11 Scala

11.1 使用 Scala 逆序遍历数组

val arr = Array(1, 2, 3, 4)

//  正常顺序
for (i <- 0 until arr.length) {
  println(arr(i))
}

//  逆序
for (i <- (0 until arr.length).reverse) {
  println(arr(i))
}

11.2 Map 集合的用法

//    创建空的 Map 集合,这里要用实现类 HashMap,因为 Map 是抽象类,使用时要声明具体实现类
var map = new HashMap[String, Int]();

//    创建 Map 集合
var map = Map("金箍棒" -> 10.0, "装甲" -> 20.0, "机枪" -> 30.0, "飞机" -> 40.0)

//    向 Map 集合中添加元素
map.put("航母", 50)

//    从 Map 集合中删除元素
map.remove("装甲")

//    遍历 Map 集合
map.foreach {
    case (key, value) => println(key, value)
    case _ =>
}

//    判断 Map 集合中是否包含某元素
println(map.contains("航母"))

//    判断 Map 集合是否为空
println(map.isEmpty)

//    只打印 key 或 value
map.keys.foreach(println)
map.values.foreach(println)

//    对 Map 集合进行排序
map.toSeq.sortBy(_._1)    //    排序 key
map.toSeq.sortBy(_._2)    //    排序 value
map.toSeq.sortBy(_._1 > _._1)    //    降序排序 key
map.toSeq.sortBy(_._2 > _._2)    //    降序排序 value

11.3 Scala 中将 Map 转换为 Java 中的 Map

var map = Map("金箍棒" -> 10.0, "装甲" -> 20.0, "机枪" -> 30.0, "飞机" -> 40.0)
var javaMap = new java.util.TreeMap[String, Double];
map.foreach{
    case (key, value) => {
        javaMap.put(key, value)
    }
    case =>
}

11.4 List 集合的用法

//    创建一个 List 集合
var list = List(1, 2, 3, 4)

//    向集合中添加一个元素
var list2 = 0 :: list

//    将两个 List 合并
var list3 = list ::: list2

//    返回第一个元素
var head = list.head

//    返回除第一个元素的 List 集合
var tailList = list.tail

//    判断 List 是否为空
var isEmpty = list.isEmpty

//    取出 List 中的偶数
var evenList = list.filter(_ % 2 ==0)

//    过滤字符串中的数字
var str = "123 hello scala 168"
var str2 = str.filter(Character.isDigit(_))

//    取出一个字符之前的所有字符
var str3 = str.toList.takeWhile(_ != 's')

//    将每个元素进行转换映射
var str4 = str.map(_.toUpper)

//    取出集合中的偶数,并为每个元素加上 100
var list4 = list.filter(_ % 2 ==0).map(_ + 100)

//    两层 List 集合
var list5 = List(list, List(4, 5, 6))

//    取出 list5 中的所有偶数,第一步 : map 获取每个 list,第二步 : filter 过滤每个 list 中的偶数元素
var list6 = list5.map(_.filter(_ % 2 == 0))

//    将 List 中的结果打平
var list7 = list5.flatMap(_.filter(_ % 2 == 0))

//    reduceLeft 和 reduceRight
var list8 = List(1, 7, 2, 9)
var result = list8.reduceLeft(_ - _)    //    ((1 - 7) -2) - 9 = -17
var result2 = list8.reduceRight(_ - _)    //    1 - (7 - (2 - 9)) = -13

//    foldLeft 和 foldRight 注 : foldLeft 和 foldRight 的简写操作中 : 均位于集合一侧,集合的位置与相应方法的名字相反
var result3 = list8.foldLeft((0)(_ - _))    //    (((0 - 1) - 7) -2) - 9 = -19
var result4 = (0 /: list8)(_ - _)    //    foldLeft 简写操作
var result5 = list8.folderRight((0)(_ - _))    //    1 - (7 - (2 - (9 - 0))) = -13
var result6 = (list8 /: 0)(_ - _)    //    foldRight 简写操作

//    foldLeft 可以用于集合中的元素反转,foldRight 不可以
var list9 = List(1, 2, 4, 3, 5)
var list10 = (List[Int]() /: list9)((x, y) => y :: x)
var list11 = (list9 :\ List[Int]())((x, y) => x :: y)

//    返回列表中的元素以指定的分隔符分割的字符串
var str5 = list.mkString(",")

//    返回列表中移除指定元素后的列表
var list9 = list.remove(_ > 1)

//    返回逆序组成的新列表
var list10 = list.reverse

//    对 List 集合进行排序 (逆序排列)
var list11 = list10.sort((num1, num2) => {
    num1 > num2
})

//    对 List 集合中的元素分组,其中每一组仍然是一个 List 集合
val list12 = List(1, 2, 4, 3, 5, 6, 7, 8)
var list13 = arr.grouped(4).toList    //    4 是指每一组中有 4 个元素,最后一组可能少于 4 个元素

11.5 Scala 中 :: 、+: 、++ 、::: 的区别

**:?*向队列的头部添加数据,创造新的列表,用法为 x :: list,其中 x 为加入到头部的元素
**+:在头部追加元素,:+**在尾部追加元素,冒号永远靠近集合类型
**++**连接两个集合,用法为 list1 ++ list2
**::?*只能用于连接两个 List 类型的集合

var list1 = List("a", "b", "c", "d")
var list2 = List("1", "2", "3", "4")

list1 :: list2 => List(List("a", "b", "c", "d"), "1", "2", "3", "4")
"e" +: list1 => List("e", "a", "b", "c", "d")
list1 :+ "e" => List("a", "b", "c", "d", "e")
list1 ++ list2 => List("a", "b", "c", "d", "1", "2", "3", "4")
list1 ::: list2 => List("a", "b", "c", "d", "1", "2", "3", "4")

11.6 Scala 中 _ 和 _* 的用法

_ 的用法 :
**作为函数的参数 ?*当函数中的参数在 => 右侧只出现一次时,可以用 _ 代替这个参数

def compute(f : (Double) => Double) = {
    f(3)
}

//    传递一个匿名函数作为 compute 的参数
compute((x : Double) => 2 * x)

//    如果参数 x 在 => 右侧只出现一次,可以用 _ 代替这个参数
compute(2 * _)

//    其它常见的使用方式
(1 to 9).filter(_ % 2 == 0)
(1 to 3).map(_ * 3)

作为通配符 :

//    在 match 中的 case 语句中使用
def matchTest(num : Int) => {
    num match{
        case 1 => "One"
        case 2 => "Two"
        case _ => "Many"
    }
}

//    可以通过模式匹配获取元组中的元素,当不需要某个值的时候可以使用 _ 代替
var tup = (1, 11.14, "Fred")
var (first, second, _) = tup

_ :*
变长参数 :

//    求和
def sum(nums : Int*) : Int = {
    var sum = 0
    for (num <- nums) {
        sum += num
    }
    sum
}

var sum1 = sum(1, 2, 3, 4, 5)
var sum2 = sum(1 to 5 : _*)    //    _* 将 1 to 5 转化为参数序列

变量声明中的模式 :

var arr = Array(1, 2, 3, 4, 5)

var Array(1, 2, _*) = arr
var Array(first, second, _*) = arr

11.7 Map 和 FlatMap 的区别

Map 是将一个数据按照一个函数进行相应的变换,返回的结果中的元素的类型可能不一致,FlatMap 是将 Map 后的数据进行压平,结果中数据为一个集合,集合中元素的类型都一样.

代码 :

object collection_t1 {

  def flatMap1(): Unit = {
    val li = List(1,2,3)
    val res = li.flatMap(x => x match {
      case 3 => List('a','b')
      case _ => List(x*2)
    })
    println(res)
  }

  def map1(): Unit = {
    val li = List(1,2,3)
    val res = li.map(x => x match {
      case 3 => List('a','b')
      case _ => x*2
    })
    println(res)
  }

  def main(args: Array[String]): Unit = {
    flatMap1()
    map1()
  }
}

结果 :

List(2, 4, a, b)
List(2, 4, List(a, b))

11.8 for 和 yield 的用法

for 的用法总结:

// 1、可以以变量<-表达式的形式提供多个生成器,用分号将它们隔开
for(i <- 1 to 3; j <- 1 to 3) {
    print((10 * i + j) + " ");
  }
 
outputs: 11 12 13 21 22 23 31 32 33

// 2、每个生成器都可以带一个守卫,以if开头的Boolean表达式
for(i <- 1 to 3; j <- 1 to 3 if i != j) {
    print((10 * i + j) + " ");
  }
 
outputs: 12 13 21 23 31 32

// 3、可以使用任意多的定义,引入可以在循环中使用的变量
for(i <- 1 to 3; from = 4 - i; j <- from to 3) {
    print((10 * i + j) + " ");
  }
 
outputs: 13 22 23 31 32 33

yield 的用法总结:
1、针对每一次 for 循环的迭代, yield 会产生一个值,被循环记录下来 (内部实现上,像是一个缓冲区).

2、当循环结束后, 会返回所有 yield 的值组成的集合.

3、返回集合的类型与被遍历的集合类型是一致的.

scala> val a = Array(1, 2, 3, 4, 5)
a: Array[Int] = Array(1, 2, 3, 4, 5)
 
scala> for (e <- a if e > 2) yield e
res1: Array[Int] = Array(3, 4, 5)

11.9 lazy 的用法

1、在类的初始化的时候可能某个变量初始化比较耗时,那么可以使用lazy,等真正使用到这个变量的时候再初始化

scala> class Person{
     |   val properties = {
     |     //模拟长时间的某种操作
     |     println("init")
     |     Thread.sleep(2000)
     |   }
     | }
defined class Person

scala> def main() {
     |   println("Start")
     | 
     |   val startTime = System.currentTimeMillis()
     |   val person = new Person
     |   val endTime = System.currentTimeMillis()
     | 
     |   println("End and take " + (endTime - startTime) + "ms")
     | 
     |   person.properties
     | }
main: ()Unit

scala> main
Start
init
End and take 2002ms

可以看到new了一个对象,需要大约2000ms,如果改成lazy变量

scala> class Person{
     |   lazy val properties = {
     |     //模拟长时间的某种操作
     |     println("init")
     |     Thread.sleep(2000)
     |   }
     | }
defined class Person

scala> main
Start
End and take 0ms
init

new操作几乎瞬间完成,而且在真正使用变量的时候才初始化的

2、构造顺序问题

trait Person{
  val name: String
  val nameLen = name.length
}

class Student extends Person{
  override val name: String = "Tom"
}

如果这时候在main函数中new一个Student,会报空指针异常
这是因为父类的constructor先与子类执行,那么在执行val nameLen = name.length的时候name还没有被赋值,所以才会导致空指针。
解决办法就是在nameLen前加lazy,延迟初始化

lazy val nameLen = name.length
相关标签: Scala