之前的基本语法包括循环什么的就不写了,直接从定义函数开始。
一、定义函数
scala中定义函数需要定义函数的名字、参数和函数体。
- 第一个示例函数:
def sayHello(name:String,age:Int) = {
if (age >= 18) {printf("hi, $s,u r bitch!!!\n",name);age}
else { printf("hi,%s,u r little bitch !!!",name); age
}
}
scala 要求给出所有参数的类型,但是不一定要求给出返回值的类型,前提是只要右侧的函数体中不包含递归的语句
- 单行的函数定义很简单:
def sayHello(name:String) = print("Hello",+name)
- 多行的代码就可以使用代码块,代码块的最后一行的返回值就是整个函数的返回值,和java不同的是,不使用return返回值
def sum(n:Int) = {
result = 0
for (i <- 1 to n) {
result += i
}
result
}
- 递归函数
与之前函数不同的是,如果在函数体内递归调用函数自身,则必须手动给出函数的返回类型。
示例为斐波那契数列:
def fab(n:Int):Int = {
if (n <= 1 ) 1
else fab(n-1) + fab(n-2)
}
二、函数之默认参数和带名参数
示例:
def sayHello(firstname:String,middlename: String = "wiliam",lastname:String = "Bob")=print("hello" + " " + firstname + " " + middlename + " " + lastname)
sayHello("leo",lastname = "jack" ,middlename = "pp")
scala中可以混合使用未命名参数和带名参数,但是未命名参数必须排在带名参数前面。
三、函数之变长参数
在scala中,有时需要将函数定义为参数个数可变的形式,可以使用变长参数定义函数
示例代码:(注意,定义函数中如果没有“=”则无返回值)
def sum(nums:Int*) = {
var result = 0
for (num <- nums) result += num
result
}
如果想要将一个已有的序列直接调用变长参数函数,直接使用sum(1 to 5)不可行,此时使用scala特殊的语法将参数定义为序列
重点!!!
val s = sum(1 to 5: _*)
示例:使用递归函数实现累加
def sum2(nums: Int*):Int = {
if (nums.length == 0) 0
else nums.head + sum2(nums.tail: _*)
}
四、函数之 过程、lazy值、异常
- 在scala中,定义函数,如果函数直接包裹在花括号中,而没有使用“=”连接,则函数的返回值类型就是Unit。这样的函数就称为“过程”,过程通常用于不需要返回值的函数。
- 过程还有一种写法,就是将函数的返回值类型定义为Unit。
示例:
def sayHello(name:String) = "hello " + name
def sayhello(name:String) {print("hello, " + name);"hello, " + name}
def sayhello(name:String): Unit = "hello, " + name
- scala中提供了lazy值的特性,如果将一个变量声明为lazy,则只有在第一次使用该变量时,变量对应的表达式才会发生计算。这种特性对于特别耗时的计算操作特别有用,比如打开文件进行IO,进行网络IO。
import scala.io.Source._
lazy val lines = fromFile("D://text.txt").mkString
- 异常
- 在scala中,异常处理和捕获机制与java非常相似。
示例:
try {
throw new IllegalArgumentException("illgal argument!!!")
} catch{
case _:IllegalArgumentException => print("sorry,error!")
} finally {
print("\nrelease io resourses!!!")
}
try {
throw new IllegalArgumentException("illgal argument!!!")
} catch{
case e1:IOException => println("io exception")
case e2:IllegalArgumentException => print("sorry,error!")
} finally {
print("\nrelease io resourses!!!")
}
一、数组操作值Array、ArrayBuffer以及遍历数组
- scala中,Array代表的含义与Java相似,也就是长度不可变的数组。此外,由于scala与java双方可以互相调用,因此scala数组的底层实际上就是java的数组。
- 数组初始化后,长度就固定下来了,而且元素全部根据其类型初始化
val a = new Array[Int](10)
val a = new Array[String](10)
- 也可以直接使用Array()创建数组,元素类型自动推断,也可以直接通过index进行修改元素
val a = Array("hello","world")
a(0) = "hi"
数组.length
可以返回数组长度
- 在scala中,如果需要类似java中ArrayList这种长度可变的集合类,则可以使用ArrayBuffer。
- 如果不想每次使用全限定名,可以先导入ArrayBuffer类
import scala.collection.mutable.ArrayBuffer
- 使用ArrayBuffer()的方式可以创建一个空的ArrayBuffer
val b = ArrayBuffer[Int]()
- 使用+=操作符,可以添加一个元素,或者多个元素。重点,spark源码里大量使用了这种集合操作语法
b += 1
b += (2,3,4,5)
- 使用 ++= 操作符,可以添加其他集合中的所有元素
b ++= Array(6,7,8,9,10)
- 使用trimEnd()函数,可以从尾部截断指定个数的元素
b.trimEnd(5)
- 使用insert()函数可以在指定位置插入元素,但是这种操作效率很低,因为需要移动指定位置后的所有元素
b.insert(5,6)
b.insert(6,7,8,9,10)
- 使用remove()函数可以移除指定位置的元素
b.remove(1)
b.remove(1,3)
- Array与ArrayBuffer可以互相进行转换
b.toArray
a.toBuffer
- 遍历Array和ArrayBuffer
- 使用for循环和until遍历Array/ArrayBuffer
for (i <- 0 until b.length) println(b(i))
- 跳跃遍历Array/ArrayBuffer
for (i <- 0 until (b.length,2)) println(b(i))
- 从尾部遍历Array/ArrayBuffer
for (i <- (0 until b.length).reverse) println(b(i))
- 使用“增强for循环” 遍历Array/ArrayBuffer
for (e <- b) println(e)
数组元素求和
val a = Array(1,2,3,4,5)
val sum = a.sum
获取数组最大值
val max = a.max
对数组进行排序
scala.util.Sorting.quickSort(a)
获取数组中的所有元素内容
a.mkString
a.mkString(",")
a.mkString("(",",",")")
ArrayBuffer的toString与Array不太一样,主要区别在于“toString”
import scala.collection.mutable.ArrayBuffer
val b = ArrayBuffer[Int]()
b += (1,2,3,4,5)
b.toString
b.mkString
二、数组操作之数组转换
- 使用yied和函数式编程转换数组
- 对Array进行转换,获取的还是Array
val a = Array(1,2,3,4,5)
val a2 = for(ele <- a) yield ele * ele
- 对ArrayBuffer进行转换,获取的还是ArrayBuffer
val b = ArrayBuffer[Int]()
b += (1,2,3,4,5)
val b2 = for(ele <- b) yield ele * ele
- 可以利用if守卫,转换仅需转换的元素
val a3 = for (ele <- a if ele % 2 == 0) yield ele * ele
- 使用函数式编程转换数组(常用的是第一种方式)
a.filter(_ % 2 == 0).map(2 * _)
a.filter{_ % 2 == 0} map{2 * _}
- 算法案例:移除第一个负数后面的所有负数
val a = ArrayBuffer[Int]()
a += (1,2,3,4,5,-1,-3,-5,-9)
var foundFirstNegative = false
var arrayLength = a.length
var index = 0
while(index < arrayLength) {
if (a(index) >= 0) {
index += 1
} else {
if (!foundFirstNegative){foundFirstNegative = true;index += 1}
else{a.remove(index);arrayLength -= 1}
}
}
- 优化后的算法
val a = ArrayBuffer[Int]()
a += (1,2,3,4,5,-1,-3,-5,-9)
var foundFirstNegative = false
val keepIndexes = for (i <- 0 until a.length if !foundFirstNegative || a(i) >= 0) yield{
if (a(i) < 0) foundFirstNegative = true
i
}
for (i <- 0 until keepIndexes.length){a(i) = a(keepIndexes(i))}
a.trimEnd(a.length - keepIndexes.length)
Map与Tuple
- 创建不可变的Map
val age = Map("leo" -> 23,"jack" -> 34)
val age = Map(("leo",12),("jack",33))
- 创建可变的Map
val ages = scala.collection.mutable.Map("leo" -> 12,"mary" -> 25)
ages("leo") = 31
- 创建空的HashMap
val ages = new.scala.collection.mutable.HashMap[String,Int]
- 访问Map的元素
val leoage = ages("leo") (如果key不存在,则报错)
使用contains函数检查是否存在
val leoage = if (ages.contains("leo")) ages("leo") else 0
getOrElse函数
val leoage = ages.getOrElse("leo",0)
- 修改可变Map的元素
更新Map的元素
ages("leo") = 31
增加多个元素
ages += ("mike" -> 34,"lucy" -> 35)
移除元素
ages -= "mike"
- 更新不可变Map的元素
val ages2 = age + ("tom" -> 23,"bob" -> 26) (这里的age是不可变Map)
- 移除不可变Map的元素
val ages3 = ages2 - "tom"
- 遍历Map
遍历Map的entrySet
for ((key,value) <- ages) println(key + " " + value)
遍历Map的key
for (key <- ages.keySet) println(key)
遍历Map的value
for (value <- ages.values) println(value)
生成新Map 反转key和value
for ((key,value) <- ages) yield (value,key)
- SortedMap可以自动对Map的key的排序
val ages = scala.collection.immutable.SortedMap("leo" -> 30,"bob" -> 23)
- LinkedHashMap可以记住插入entry的顺序
Map的元素类型——Tuple
面向对象编程之类
- 定义类,包含field方法
class HelloWorld{
private var name = "leo"
def sayHello(){print("hello," + name)
def getname = name
}
- getter与setter
- 自定义getter和setter
- 如果只是希望拥有简单的getter和setter方法,那么就按照scala提供的语法规则,根据需求为field选择合适的修饰符就好:var、val、private、private[this]
- 但是如果希望能够自己对getter和setter进行控制,则可以自定义getter和setter方法
- 自定义setter方法的时候一定注意scala的语法规则,签名、=、参数之间不能有空格
class Student{
private var myName = "leo"
def name = "your name is " + myName
def name_=(newValue:String){
print("you cannot edit your name!")
}
}
- 仅暴露field的getter方法
class Student{
private var myName = "leo"
def updateName(newName:String){
if (newName == "leo1") myName = newName
else println("not accept this new name," + newName)
}
def name = myName
}
- private[this]的使用
class Student{
private var myAge = 0
def age_=(newValue:Int){
if (newValue > 0) myAge = newValue
else print("illegal age!")
}
def age = myAge
def older(s:Student) = {
myAge > s.myAge
}
}
class Student{
private[this] var myAge = 0
def age_=(newValue:Int){
if(newValue > 0) myAge = newValue
else println("illegal age!")
}
def age = myAge
def older(s:Student) = {
myAge > s.myAge
}
}
- java风格的getter和setter方法
import scala.beans.BeanProperty
class Student{
@BeanProperty var name:String = _
}
或者
class Student(@BeanProperty var name:String)
- 辅助 constructor
class Student{
private var name = ""
private var age = 0
def this(name:String){
this()
this.name = name
}
def this(name:String,age:Int){
this(name)
this.age = age
}
}
- 主constructor
class Student(val name:String,val age:Int){
println("your name is "+ name +",your age is "+ age)
}
class Student(val name:String = "leo ",val age:Int = 30){
println("your name is "+ name +",your age is "+ age)
}
- 内部类
import scala.collection.mutable.ArrayBuffer
class Class{
class Student(val name:String)
val students = new ArrayBuffer[Student]()
def getStudent(name:String) = {
new Student(name)
}
}