Scala语言学习
scala语法
函数式编程
面向对象
集合类型
计算函数
* 调用方法时"."可以省略
scala语法
1、常量与变量
val:修饰常量 var:修饰变量
//以下滑行开头 val _abc="abc" //已操作符开头,且只能包括操作符 val +-*/%^ = "hello" //可以使用反引号将保留字作为变量名称 val `if`="if" println(`if`)
2、数据类型

//空值 Unit def m1: Unit = { println("m1被调用") } val m: Unit = m1 println(m) //空引用 Null,只能给引用类型复制 // val num:Int=null 错误的 var stu: Stu = null println(stu) var str: String = null println(str) //Nothing def m2(num: Int): Int = { if (num == 0) { throw new NullPointerException } else { num + 1 } } def m3(num: Int): Nothing = { throw new NullPointerException } val m22 = m2(2) println(m22)
3、数据转换
4、运算符
5、流程控制
(1)简单的控制
//if语句可以带有返回值 println("------if语句可以带有返回值-----") var var1 = if (1 > 3) { println("123") "123" } else { println("123") "456" } println(var1) //类似三元运算符 println("------类似三元运算符-----") var var2 = if (1 > 3) "123" else if (1 < 5) "456" else "789" println(var2)
(2)for循环控制
//循环推导式 println("------循环推导式-----") for (i <- 1 to 3) { println(i) } for (i <- 1 until 3) { println(i) } for (i <- Range(1, 4)) { println(i) } for (i <- Array(1, 4)) { println(i) } //循环保卫 println("------循环保卫-----") for (i <- 1 to 3 if i % 2 != 0) { println(i) } //循环步长 println("------循环步长-----") for (i <- 1 to 10 by 2 if i % 3 != 0) { println(i) } for (i <- 1 to 10 by -2) { println(i) //无法到达时改语句不执行 } //嵌套循环(双重for循环 println("------嵌套循环-----") for (i <- 1 to 3; j <- 2 to 3) { println(i + " " + j) } //引入变量 println("------引入变量-----") for (i <- 1 to 3; j = i * 2) { println(i + " " + j) } for //变形 {i <- 1 to 3 j = i * 2} { println(i + " " + j) } //循环返回值 使用yield关键字,指定for返回值,与多线程无关 println("------循环返回值-----") val forRe: immutable.IndexedSeq[Int] = for (i <- 1 to 3) yield i println(forRe) //循环中断 scala中删除了break和continue println("------循环中断-----") try { for (i <- 1 to 3 ) { if(i==2){ throw new Exception } println(i) } }catch { case e:Exception=> } //使用breaks类中断 Breaks.breakable( for (i <- 1 to 3 ) { if(i==2){ Breaks.break() } println(i) } ) //再简化 breakable( for (i <- 1 to 3 ) { if(i==2){ break } println(i) } ) println("抛出异常中断for")
函数式编程
1、函数定义
//可变参数 println("-----可变参数-----") def f1(str:String*):Unit={ println(str) } f1("str1","str2") //参数的默认值 println("-----参数的默认值-----") def f2(str:String="wgy"):Unit={ println(str) } f2() f2("str1") //带命参数,赋值可指定名称赋值 println("-----带命参数-----") def f3(str:String="str",age :Int):Unit={ println(s"name${str} age${age}") } f3(age = 18,str = "wgy") f3(age = 25)
2、匿名函数
/* 函数省略 */ println("函数省略") //定义一个匿名函数 val myFun: String => Unit = (name: String) => { println(name) } //定义一个入参为函数的函数 def func(thisFun: String => Unit): Unit = { thisFun("wgy scala") } //将匿名函数传入自定义函数中 func(myFun) //1、定义的匿名函数入参类型可以省略 //2、当只有一个入参时,入参的括号以省略 //3、匿名函数只有一行,大括号可以省略 func(name => println(name)) //1、当参数只出现一次,入参可以省略后边参数用_代替 //2、能推断出是一个函数题的话可以直接省略(_)如:func(println) func(println(_)) //如果可以推断出,出入的是函数体,不是调用语句,下划线也可以省略 func(println) /* 函数作为值返回 */ println("函数作为值返回") def f(a: Int): Int = { a + 123 } //函数作为值传递 val f2: Int => Int = f //指定f2的类型后既可以把f当做整体传值 val f1 = f _ //如果省略f1的类型时需要加一个空格下划线表示整体,如果没有下划线表示调用该函数了
3、闭包柯里化
闭包:如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和它所处的环境,称为闭包。
函数柯里化:把一个参数列表的多个参数,变成多个参数列表
/* 柯里化 */ def f1(num1: Int): Int => Int = { def f2(num2: Int): Int = { num1 + num2 } f2 _ } val intToInt1: Int => Int = f1(456) println(intToInt1(678)) println(f1(456)(789)) //可以简化为 def f2(num1: Int)(num2: Int): Int = { num1 + num2 } val intToInt2: Int => Int = f2(12) println(intToInt2(678)) println(f2(456)(789))
3、递归函数
//递归函数 println("-----递归函数-------") def factorial(n: Int): BigInt = { if (n <= 0) 1 else n * factorial(n - 1) } println(factorial(5)) /*尾递归 为优化栈溢出问题,使用尾递归 即自身的最后一行函数直接返回调用自身,不做其他操作 */ println("-----尾递归-------") def factorialTailrec(n: BigInt, acc: BigInt = 1): BigInt = { if (n <= 1) acc else factorialTailrec(n - 1, acc * n) } println(factorialTailrec(5))
4、控制抽象
/** * 控制抽象 */ //传值参数,常用形式 println("------传值参数------") def f0(a:Int):Unit={ println(a) println(a) } def f1():Int={ println("函数f1被调用") 12 } f0(f1) /* 传名参数 将整个代码块传入,函数中该参数使用了几次,代码块就会被调用几次 */ println("------传名参数------") def f2(a: =>Int):Unit={ println(a) println(a) } def f3(a:Int):Int={ println("函数f2被调用") a } f2(f3(13))
5、使用柯里化实现while
//方式1:使用普通方式实现 def myWhile1(isdo: => Boolean): (=> Unit) => Unit = { def doLoop(op: => Unit): Unit = { if (isdo) { op myWhile1(isdo)(op) } } doLoop _ } //方式2:使用匿名函数实现 def myWhile2(isdo: => Boolean): (=> Unit) => Unit = { val myf=(op: =>Unit) => { if (isdo) { op myWhile2(isdo)(op) } } myf } //方式3:使用柯里化方式实现 def myWhile3(isdo: => Boolean)(op: => Unit): Unit = { if (isdo) { op myWhile3(isdo)(op) } } //测试 var n = 5 myWhile2(n > 0) { println(n) n -= 1 }
6、懒加载关键字lazy
val sum = (a: Int, b: Int) => { println("开始结算") a + b } lazy val num = sum(1, 2) println("开始输出结果") println("输出结果1" + num) println("输出结果2" + num)
面相对象
1、包对象(package Object)
在scala中可以为每个包定义一个同名的包对象,定义在包对象中的成员,作为其对应包下所有class和object的共享变量,可以直接被访问
一个包下可以生成一个,只有当前包下的类可以使用,子包也不可用
package com package object wgy { def commMethod(): Unit = { println("wgy 学习sacls") } var mess: String = "13213213" }
2、类和对象
import scala.beans.BeanProperty class Stu() { /* 1、@BeanProperty:声明处get、set 2、如果要给参数空值时使用下划线 */ private var name:String="wgy" @BeanProperty var age:Int=18 @BeanProperty var sex:Boolean=_ } object Stu { def main(args: Array[String]) = { val stu: Stu = new Stu println(stu.name) println(stu.age) println(stu.sex) } }
2、构造器
import scala.beans.BeanProperty //主构造器 class Student { @BeanProperty var name: String = _ @BeanProperty var age: Int = _ println("Student类主构造器被调用") //辅助构造器,需要直接或者间接调用主构造器,且必须放在构造器的第一行,可多个 def this(name: String) { this() this.name = name } def this(name: String, age: Int) { this(name) this.age = age } def mothed() = { println("执行Student类中方法") } } /* 使用var指定为带参数的主构造器 带有var类似定义一个属性 不带传入仅仅是一个局部变量 */ class Student2(var name: String, var age: Int) class Student3(name: String, age: Int) class Student4() extends Student { //重写方法是需要增加override override def mothed() = { println(s"执行Student3类中方法${name},${age}") } } object Student { def main(args: Array[String]): Unit = { val student4: Student4 = new Student4 student4.mothed() } }
3、继承
/** * 测试,输出结果 * 1、父类主构造器函数本调用 2、父类辅助构造器函数本调用 3、子类主构造器函数本调用 4、子类辅助构造器函数本调用 父类展示name:wgy,age:18 子类展示name:wgy,age:18,id:100001 * */ object Per { def main(args: Array[String]): Unit = { val stu: Stu = new Stu("wgy", 18, "100001") stu.show } } /** * 父类 */ class Per { var name: String = _ var age: Int = _ println("1、父类主构造器函数本调用") def this(name: String, age: Int) { this() println("2、父类辅助构造器函数本调用") this.name = name this.age = age } def show: Unit = { println(s"父类展示name:${this.name},age:${this.age}") } } /** * 子类 * 子类继承父类, 此时父类可以传入参数 * 在调用子类主构造器之前会先调用父类构造起器 */ class Stu(name: String, age: Int) extends Per(name, age) { var id: String = _ println("3、子类主构造器函数本调用") def this(_name: String, _age: Int, _id: String) { this(_name, _age) println("4、子类辅助构造器函数本调用") this.id = _id } override def show: Unit = { super.show println(s"子类展示name:${this.name},age:${this.age},id:${id}") } }
4、多态(与java一致)
5、抽象类
集合类型
三大集合:序列Seq、集Set、映射Map
对于集合类,scala提供了可并与不可变的版本
不可变集合:scala.collection.immutable
可变集合:scala.collection.mutable
1、数组
不可变数组(不可变指的长度不可变,其位置上的值是可以赋值的)
//创建不可变数组
val array1: Array[Int] = new Array[Int](5)
//使用伴生对象创建对象
val array2: Array[Int] = Array(4, 5, 6, 7)
//数组赋值
array2(2) = 1000
//访问数组
println(array2.apply(2))
//遍历数组
for (i <- array2.indices) println(array2(i)) //根据下标循环
for (elem <- array2) println(elem) //增强for循环
array2.foreach(println)
val iterator: Iterator[Int] = array2.iterator //遍历器循环
while (iterator.hasNext)
println(iterator.next())
//连接素连接转为String输出
println(array2.mkString("--"))
//添加元素(创建新的数组返回)
array2.:+(789) //往末尾追加数据
array2 :+ 789 //功能同上,放大调用时可以将.用空格代替或者省略;参数只有一个时可以将括号省略
array2.+:(456) //往数组前追加数据
456 +: array2 //功能同上,当方法名称以:结尾时,此时方法左边为参数右边为对象(:在对象测)
//创建多维数组
val array3: Array[Array[Int]] = Array.ofDim(2, 2)
可变数组
val buffer: ArrayBuffer[Int] = new ArrayBuffer
val buffer2: ArrayBuffer[Int] = ArrayBuffer(12, 45, 78, 1998)
//访问元素
println(buffer2(0))
//添加元素
buffer2 :+ 999
999 +: buffer2 //以上两种方法不会在本数组添加,需要在返回的新数组中操作
buffer2 += 999 //在数组前追加元素,返回原数组(操作符不推荐在可变数组中使用)
888 +=: buffer2 //由于scala只会对结尾为:的方法处理为参数在前对象在后,所以要想在数组前追加元素,需要加:
buffer2.append(1, 2, 3, 4) //在数组前追加(推荐使用方法调用)
buffer2.prepend(9, 8, 7, 6) //在数组后添加
buffer2.insert(1, 1998) //在指定位置添加元素
buffer2.insertAll(1, buffer) //在指定位置添加数组
//删除元素
buffer2.remove(buffer2.size - 1) //在指定下标后删除一个元素
buffer2.remove(buffer2.size - 1, 1) //在指定下标后删除n个元素
buffer2 -= 1998//按值删除,删除首次出现的第一个该元素
//可变数组互转为不可变数组
val array: Array[Int] = buffer2.toArray
val buffer3: mutable.Buffer[Int] = array.toBuffer
2、List列表
不可变列表(不可变指的内容,长度均不可变)
//创建列表
val list1: List[Int] = List(1, 2, 3, 4, 5) //使用伴生对象的apply生成对象
val list2: List[Int] = Nil.::(789) //使用Nil的::方法生成对象
val list3: List[Int] = 789 :: Nil //由于::方法以:结尾,固可以省略后使用参数在前对象在后方是调用
val list4: List[Int] = 789 :: 456 :: 123 :: 147 :: Nil //结合多个从后向前创建得到
//添加元素(与数组类似)
val listNew: List[Int] = 465 +: list1 :+ 798
//合并列表
val list5: List[Any] = list3 :: list4//不会合并两list,是将list3作为元素添加到list4头
val list6: List[Any] = list3 ::: list4//合并两List
val list7: List[Any] = list3 ++ list4//功能同上,合并两List
可变列表
//创建可变列表
val list1: Any = new ListBuffer[Int]()
val list2: ListBuffer[Int] = ListBuffer(123, 456, 798)
val list3: ListBuffer[Int] = ListBuffer(777, 888, 999)
//合并可变List
val list4: ListBuffer[Int] = list2 ++ list3 //将两个List合并后返回新的list
list2 ++= list3 //将list3追加到list2队尾,并返回list2
list3 ++=: list2//追加到list2队首
//操作队列
list2.append(555)
list2.remove(1,2)
list2.update(1,10)
list2-=15//根据值删除元素
3、Set集合
不可变Set
//创建不可变Set
val set1: Set[Int] = Set(1, 2, 3, 4, 4, 5, 6, 7)
//添加元素
val set2: Set[Int] = set1.+(789)
val set3: Set[Int] = set1 + 456
//合并set
val set4: Set[Int] = set2 ++ set3
//删除元素
val set5: Set[Int] = set4 - 789
可变Set
//创建可变Set
val set1: mutable.Set[Int] = mutable.Set(1, 2, 3, 4, 4, 5, 7)
//添加元素
val set2: mutable.Set[Int] = set1 + 100 //原set不变,返回新的set
set1 += 555 //在set1中添加元素
set1.add(666) //同上
//删除元素
set1 -= 555
set1.remove(666)
//合并set
val set3: mutable.Set[Int] = set1 ++ set2
4、Map集合
不可变Map
//创建不可变Map
val map1: Map[String, Int] = Map("wgy" -> 10, "wll" -> 20, "whh" -> 18)
//访问元素
val maybeInt: Option[Int] = map1.get("wgy")
val value: Int = maybeInt.get//调用get方法获取对应值(None.get报错,Some.get返回值)
val value2: Int = map1.getOrElse("wgy",18)//直接获取值
val value3: Int = map1("www")//当值不存在报错
map1.keys.foreach(println)//遍历
可变Map
//创建可变Map
val map1: mutable.Map[String, Int] = mutable.Map("wgy" -> 10, "wll" -> 20, "whh" -> 18)
//添加元素
map1.put("wnb",100)
map1+=(("wnb",200))
map1.update("wnb", 300)
val map2: mutable.Map[String, Int] = map1.updated("wnb", 666)//区别update,该方法返回新对象
map2.remove("wgy")
//合并map
map1++=map2
5、元组
val tuple: (Int, String, Char, Boolean) = (1, "1", 'a', true)
tuple.productIterator.foreach(println)
6、可变队列
val queue: mutable.Queue[Int] = new mutable.Queue[Int]()
queue.enqueue(1,2,3,4,5,6,111)
val va: Int = queue.dequeue().
计算函数
1、转换类函数
val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8)
//过滤
val re: List[Int] = list.filter(_ % 2 == 0)
//map
val re2: List[Int] = list.map(_ * 2)
//扁平化
val list1: List[List[Int]] = List(List(1), List(11, 12), List(21, 22, 23), List(31, 42, 43, 44))
val flatten: List[Int] = list1.flatten
//扁平映射(结合map与flatten)
val re3: List[Int] = list1.flatMap(list => {
list :+ 999 //对数据中的元素添加一个数字再扁平化
})
//分组
val re5: Map[Int, List[List[Int]]] = list1.groupBy(_.size)
val re6: Map[Int, List[Int]] = list.groupBy(_ % 2)
2、规约类函数
val re7: Int = list.reduce(_ + _) //reduce聚合操作
val re8: Int = list.fold(100)(_ + _) //类似reduce,第一个参数给定初始值
val map1: Map[String, Int] = Map("a" -> 1, "b" -> 2, "c" -> 3, "d" -> 4)
val map2: Map[String, Int] = Map("a" -> 10, "b" -> 20, "cc" -> 30, "dd" -> 40)
val map: Map[String, Int] = map1 ++ map2
println(map == map1)
val stringList: List[String] = List("wgy", "wgy 123", "wgy 465 798", "wll wgy", "wll 123")
val list2: List[String] = stringList.flatMap(_.split(" "))
val map3: Map[String, List[String]] = list2.groupBy(w => w)
val map4: Map[String, Int] = map3.map(kv => (kv._1, kv._2.size))
val tuples: List[(String, Int)] = map4.toList.sortWith((a, b) => a._2 > b._2).take(3)
println(tuples)
3、并行执行
val strings: immutable.IndexedSeq[String] = (1 to 5).map(x => Thread.currentThread().getName)
val strings1: ParSeq[String] = (1 to 5).par.map(x => Thread.currentThread().getName)
println(strings1)
3、模式匹配
val x: Int = 5
val y: Int = x match {
case 0 =>
println("798")
798
case 1 =>
println("458")
458
case _ =>
println("111")
111
}
//模式守卫(可以对范围做匹配,我没明白if else不好使吗)
val z: Int = x match {
case i if i > 0 =>
println("798")
798
case i if i == 0 =>
println("458")
458
case _ =>
println("111")
111
}
//匹配常量
def match1(x: Any): Unit = x match {
case 1 => println("Int 1")
case "wgy" => println("String wgy")
case true => println("boolean true")
case '+' => println("")
}
//匹配类型
def match2(x: Any): Unit = x match {
case i: Int => println("798")
case s: String => println("458666")
case list: List[String] =>
println("458777") //注意List的泛型匹配时存在泛型擦除,导致泛型被忽略所有List的类型都会匹配
case list: Array[String] => println("458888") //注意Array不存在泛型擦除
case a => println("111")
}
//匹配数组、列表(List)、元祖同理(自上而下匹配,当匹配到后边将不再匹配)
for (elem <- List(Array(1, 0, 1), Array(1, 1), Array(0, 1), Array(0))) {
elem match {
case Array(0, _) => println("(0,_)") //必须有两个元素,且第一个元素为0
case Array(0, _*) => println("(0,...)") //匹配开头0,后边有多个或者没有元素的数组类型
case Array(1, 1) => println("(1,1)")
case Array(x, y) => println("(x,y)")
case Array(x, 0, z) => println("(x,0,z)")
case _ => println("_")
}
}
//元组
val (xx, yy) = (1, "wgy") //相当于x=1,y="wgy"
val List(first, second, _*) = List(2, "wll", 465, 798) //first=2,second=wll
val fir :: sec :: rest =
List(1, 2, 3, 4, 5) //区别上边fir=1 ,sec=2 ,rest=List(3,4,5)
val list: List[(String, Int)] =
List(("a", 1), ("b", 2), ("c", 3), ("d", 4), ("e", 1666))
for ((v1, v2) <- list) println(v1 + ":" + v2)
for (("a", v) <- list) println(v) //相当于过滤了第一个元素为”a“的
浙公网安备 33010602011771号