scala 官网地址:https://www.scala-lang.org/
1.手动编译scala文件
vim一个文件HelloScala.scala,写入如下代码:
object HelloScala {
def main(args: Array[String]): Unit = {
println("Hello Scala! ")
}
}
运行:scalac HelloScala.scala 生成字节码文件。
运行:scala HelloScala 运行字节码文件,输出结果。
2.顶层接口:Any
AnyVal:值类型(数值、boolean、Unit)
AnyRef:引用类型
3.递归必须写明返回值类型
def mult(i:Int):Int = {
if( i<=1 ) {
1
} else {
i * mult(i-1)
}
}
4.to和until 都是Range,都是immutable类型
1 to 10 等价于 1.to(10) 左闭右闭 [ ]
1 until 10 等价于1. until (10) 左闭右开 [ )
Range默认为步长为1的左闭右开集合。如Range(1,10,2) 表示 Range(1,3,5,7,9),
也可以倒序,如Range(10,-1,-1),每次步长减一。
1 to 100 by 10表示Range(1,11,21,31,41,51,61,71,81,91),等价于1.to(100,10)。
5.遍历
val array = Array(1,2,3,4,5)
//方式一
for(ele <-array){
println(ele)
}
//方式二
array.foreach(ele=>println(ele))
//方式三
val result = for(ele <- array) yield ele * 10
result.foreach(println)
6.1-100求和
var (sum, index) = (0, 100)
while (index > 0) {
sum = sum + index
index = index - 1
}
println(sum)
7.调用包含默认参数的方法
包含默认参数的方法,调用时,若直接使用默认参数,必须带上括号,不能省略括号。
def loadconf (name: String = "spark-conf") = {
println (name)
}
loadconf ()
8.可变参数
def sum(nums: Int*) = {
var result = 0
for (num <- nums) {
result += num
}
result //返回值
}
println(sum(1, 2, 3, 4, 5))
println(sum(1 to 10: _*))
9.函数和方法的区别
def定义的是方法,函数的标识是=>。
函数的定义1:
val/var 函数名称 = (参数列表) => {函数体}
如:
val f1 = (a: Int, b: Int) => a + b
println(f1(2, 3))
匿名函数: (a:Int, b:Int)=>a+b
函数的定义2:
val/var 函数名称:(输入参数类型) => 返回值类型 =(输入参数的引用)=> {函数体}
如:val f2: (Int, Int) => Int = (a, b) => a + b
10.占位符的使用
使用占位符的前提是一定要指明数据类型。
如:var name:String = _
11.各数据类型的默认值
String的默认值是null
Int的默认值是0
Boolean的默认值是false
Double的默认值是0.0
12.构造和继承
定义class时,可以将参数定义在构造器中,也可以写到属性里。参数定义在属性里,若是private修饰,外部是无法访问的,参数定义在构造器中,必须加上val/var外部才能调用,否则也相当于私有的。
如:
class Person(val name: String, val age: Int) { //主构造器
val job = ""
var team = ""
/**
* 附属构造器的名称是this
* 每个附属构造器的第一行必须调用主构造器或者其他附属构造器
*/
def this(name: String, age: Int, team: String) {
this(name, age)
this.team = team
}
}
/**
* 子类构造方法/构造器执行前一定要先执行父类的构造器
* 对于父类没有的字段,要使用val/var修饰,否则访问不到
*/
class student(name: String, age: Int, val major: String) extends Person(name, age) {
// 子类重写父类的属性或方法,必须父、子都使用val修饰
override val job: String = "teacher"
}
13.抽象类
- 抽象类中有一个或多个方法/属性的定义没有实现。
- 使用时要有完全实现了抽象方法/属性的子类才行。
- 子类重写父类方法或属性时不一定需要写overwrite关键字。
abstract class Person2{
def speak
val name: String
}
14.伴生类和伴生对象
一般情况下,object的apply方法的作用是完成new class,
形如:类名() -> Object apply (很常用)
对象() -> Class apply (很少用)
15.定长数组
val a = new Array[String](5)
a(1) = “hello”
val a = new Array(5) 此时数组类型是Nothing
val a: Null = _
val a = Array(“aaa”,”bbb”,”ccc”)
16.变长数组
ArrayBuffer(scala.collection.mutable)
val c = ArrayBuffer[Int]()
c.length 等于0
c += 1
c += (3,4,5)
c ++= Array(6,7,8) 添加不可变的数组时需要两个加号
c.insert(0,1) 第0个位置放入1
c.remove(1) 移除指定位置元素
c.remove(0,3) 从第0 个位置移除3个元素
c.trimEnd(2) 删除尾部的两个元素
c.toArray 转成定长数组
17.数组反转
方式一:
a.reverse
方式二:
for (i <- a.length - 1 to 0 by -1) {
println(a(i))
}
18.数组拼接
val a1 = Array(1,3)
val a2 = Array(2,4)
a1 ++ a2 // ++方法用于连接两个集合,list1++list2
a1.max
a1.min
a1.sum
val a = Array(“aaa”,”bbb”,”ccc”)
println(a.mkString(“,”))
println(a.mkString(“[”, “,” ,”]”))
注意:scala中:: , +:, :+, :::, +++ 4种操作符的区别
19.元组
用括号括起来,可以装任何类型。
20.map: 一一映射
val a: Array[Int] = Array(1, 2, 3, 4, 5, 6)
a.map(x => x * 2)
a.map(_ * 2)
val array = Array(Array(("ruoze", 30)), Array(("jepson", 18)))
array.map(x => x.map(t => (t._1, t._2+2)))
21.filter:过滤,留下为true的,排除为false的
val a: Array[Int] = Array(1, 2, 3, 4, 5, 6)
a.map(_ * 2).filter(_ > 4)
a.take(4)
a.reduce(_ + _)
a.reduceLeft(_ + _)
a.reduceRight(_ + _)
a.reduce(_ - _)
22.zip:拉链
只有同等的位置上有元素才拉链,没有的不输出,如a有5个,b有4个,结果输出还是4个。
val a = List(1, 2, 3, 4)
val b = List("A", "B", "C", "D")
a.zip(b) // 输出List((1,A),(2,B),(3,C),(4,D))
val f = Array(Array(1, 2), Array(3, 4), Array(5, 6))
f.flatten // 输出Array(1,2,3,4,5,6)
// flatMap = flatten + map
f.flatMap(_.map(_ * 2)) //输出Array (2,4,6,8,10,12)
val l = Array("hello,word,welcome", "ruoze,jepson")
l.map(x => x.split(",")).flatten
val a = Array(1, 2, 3, 4, 5, 6)
a.find(_ > 3) //输出Some(4),找出满足条件的第一个元素
23.groupBy分组
val arrs = Array(("a",100),("b",10),("a",190),("d",10))
arrs.groupBy(x => x._1)
输出Map(b->Array((b,10)), d->Array((d,10)), a->Array((a,100),(a,190)))
排序:字符就按字典字典顺序排,数字就按大小排
val a = Array(“c”,“b”,“a”)
a.sorted 默认升序,输出Array(a,b,c)
a.sorted(x => -x) 实现降序
24.mapValues
直接对 (key,value) 的value值进行操作。
25.WordCount
val data = Array("hello world hello", "hello world")
val words: Array[String] = data.flatMap(_.split(" "))
val wordWithOne: Array[(String, Int)] = words.map((_, 1))
val groupByData: Map[String, Array[(String, Int)]] = wordWithOne.groupBy(_._1)
val map: Map[String, Int] = groupByData.mapValues(_.map(_._2).sum)
val list: List[(String, Int)] = map.toList
val result: List[(String, Int)] = list.sortBy(-_._2)
result.foreach(println)
26.字符串插值
val name = "ruozedata"
val welcome = "hello" + name // 一般不用这种方式
println(s"hello:${name}")
27.定义多行字符串
val msg =
"""
|这是一个多行字符串
|Hello
|ruozedata
""".stripMargin
println(msg)
28.定长的 List(有序、可重复)
Nil是什么?
scala.collection.immutable.Nil.type = List()
val list = List(1,2,3,4,5)
list.head // 代表list的第一个元素。
list.tail // 代表list除了第一个元素剩下的元素。
val l2 = 1 :: Nil // ::是List中的方法,拼接
val l3 = 2 :: l2
val l4 = 1 :: 2 :: 3::Nil // 返回List(1,2,3)
29.变长的 List
val l5 = scala.collection.mutable.ListBuffer[Int]()
l5 += 2
l5 += (3, 4, 5)
l5 ++= List(6, 7, 8, 9)
l5 -= 3
l5 -= (1, 4)
l5 --= List(5, 6, 7, 8)
l5.toList // 变长转定长
l5.toArray // 转成数组
30.递归实现求和
def sum(nums:Int*) : Int = {
if(nums.length == 0) 0
else nums.head + sum(nums.tail :_*)
}
println(1,2,3,4,5,6)
31.取值
取tuple中的值用圆括号加index,取List中的值用下划线。
val names = List("CXK","苏大强","谢广坤")
val scores = List(5, 9, 4)
val results = names.zip(scores)
val res = results.zipWithIndex.zipWithIndex
println(res) // List((((CXK,5),0),0), (((苏大强,9),1),1), (((谢广坤,4),2),2))
println(res(2)._1._1._1) // 取出谢广坤
32.Set
val set = Set(1,1,2,2,3,3)
返回 scala.collection.immutable.Set[Int] = Set(1,2,3),实现自动去重。
其他方法同List用法
33.Map
分为可变的和不可变的
val a = Map(“ruoze”->30,“jepson”->18)
取值用:a(“ruoze”)
默认是不可变的,可变的需要写成:
scala.collection.mutable.Map(“ruoze”->30,“jepson”->18)
添加元素:b(“canlaoshi”)=38
b += (“longlaoshi”->27, “bolaoshi”->31)
删除元素:b -= “ruoze”
修改元素:b(“canlaoshi”)=30
是否包含:b.contains(“canglaoshi”)
查询元素:Map中没有的元素会报错,解决办法:
b.getOrElse(“longlaoshi”, 40) // 取不到值就返回默认40
遍历元素:
for((k,v) <- map) {
println(k + "->" + v)
}
或
for(k <- map.keySet) {
println(k + "->" + map.getOrElse(k, -99))
}
或
for(v <- map.vaules) {
println(v)
}
或
for((k,v) <- map) {
println(k + "->" + map.getOrElse(k, -99))
}
可排序的Map:
scala.collection.immutable.SortedMap
scala.collection.mutable.LinkedHashMap
34.Option
Option是一个抽象的类,包含Some、None
val m = Map(1 -> 2)
m(1) // 返回Int = 2
m.get(1) //返回Option[Int] = Some(2)
m.get(1).get //返回Int = 2
m.get(2) //返回Option[Int] = None
m.get(2).getOrElse("None")
35.case class 样例类
case class Person(name: String, age: Int)
val p3 = Person("ruoze", 30)
val p4 = Person("ruoze", 30)
p3 == p4 //返回true
case class和class的区别:
1.case class 重写了toString、equals、hashCode
2.case class 默认实现了序列化
3.case class 必须要有参数列表
(case object 必须不能加参数列表)
4.case class 不用new
36.trait
aaa extends bbb with ccc with ddd {}
不管有多少个类或特质需要继承或实现,第一个用extends,后面的都用with。
37.模式匹配:匹配内容、匹配类型、匹配集合、匹配case xxx、匹配异常
样例:
变量 match{
case A => codeA
case B => codeB
case C => codeC
case _ => code
}
匹配内容:
val teacher = Array("a","b","c")
val name = teacher(Random.nextInt(teacher.length))
name match {
case "a" => println{"A"}
……
case _ => println{"x"}
}
匹配类型:
def matchType(obj : Any) = obj match {
case x:Int => println("Int")
case s:String => println("String")
case _ => println("other")
}
matchType(1)
matchType("abc")
匹配集合:
def matchList(list:List[String]):Unit = {
list match {
case "ruoze"::Nil => println("ruoze") // 只能匹配只有一个ruoze元素的集合
case x::y::Nil => println(s"$x,$y") // 只能匹配只有两个元素的集合
case "jepson"::tail => println("jepson and other") //匹配jepson开头的集合
case _ => println("……")
}
}
匹配case xxx:
case class Submit(id:String, name:String)
case class Beat(time:Long)
case Object TimeOutTask
val caseclass = Array(TimeOutTask, Beat(1000),Submit("10","task"))
caseclass(Random.nextInt(3)) match {
case TimeOutTask => println("TimeOutTask ")
case Beat(time) => println("Beat")
case Submit(id, name) => println("Submit")
}
匹配异常:
try{
//TODO 业务逻辑
} catch {
case e:ArithmeticException => println("除数不能为0")
case e:Exception => e.printStackTrace()
} finally {
// 资源释放
// close
}
38.currying 柯里化
def sum(a: Int, b: Int) = a + b
println(sum(3, 5))
def sum2(a: Int)(b: Int) = a + b
println(sum(4)(5))
39.偏函数
偏函数:包在花括号内没有match的一组case语句。
val teacher = Array("a", "b", "c")
val name = teacher(Random.nextInt(teacher.length))
// A:输入参数类型
// B:输出参数类型
def say: PartialFunction[String, String] = {
case "a" => "ABC"
case "b" => "BCD"
case _ => "……"
}
println(say(name))
40.文件操作
val content = Source.fromFile("E:\\ruoze.txt")
def read(): Unit = {
for (line <- content.getLines()) {
println(line)
}
}
read()
41.闭包
闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。
闭包通常来讲可以简单的认为是可以访问一个函数里面局部变量的另外一个函数。
如下面这段匿名的函数:
val multiplier = (i:Int) => i * 10
函数体内有一个变量 i,它作为函数的一个参数。如下面的另一段代码:
val multiplier = (i:Int) => i * factor
在 multiplier 中有两个变量:i 和 factor。其中的一个 i 是函数的形式参数,在 multiplier 函数被调用时,i 被赋予一个新的值。然而,factor不是形式参数,而是自由变量,
var factor = 3
val multiplier = (i:Int) => i * factor
这里我们引入一个自由变量 factor,这个变量定义在函数外面。
这样定义的函数变量 multiplier 成为一个"闭包",因为它引用到函数外面定义的变量,定义这个函数的过程是将这个自由变量捕获而构成一个封闭的函数。