上一篇文章介绍了如何下载scala, 因为在官网上点击下载按钮无法下载,
下面介绍scala的基础语法:
1 scala和java的关系
Scala是基于jvm的一门编程语言,Scala的代码最终会经过编译成字节码,交给java虚拟机来运行
Scala和java可以无缝互操作,Scala可以任意调用java代码、
2 Scala的解释器 repl
scala的解释器会快速编译scala代码为字节码然后交给jvm来执行。
repl : read 取值 ---> evaluation 求值 ----> print 打印 ----> loop 循环
3 声明变量和常量和指定类型
声明变量使用 var 这个和 js类似
声明常量使用 val 声明常量赋值后 这个常量将不能再被改变值
定义中建议使用常量声明,类似于spark的大型复杂系统中,需要大量网络传输数据,如果使用var 可能会担心值被错误的更改,这个类似于java中使用final关键字来
提高系统健壮性一样。
eg: var name:String = "zm"
var name1, name2:String = "zm"
4 数据类型和操作符
基本数据类型: Byte、Char、Short、Int、Long、Float、Double、Boolean。 和java的包装类型一致,没有基本数据类型
操作符: 和java的操作符一致, 唯一区别是 ++ --没有, 比如 a++ 必须写成 a += 1
5 函数调用
调用函数如果不需要传递参数 那么 scala 允许省略掉括号。
6 块表达式:
指的就是{}中的值, 最后一个语句的值就是块表达式的返回值。
eg:
var a = 1;
var b = 2;
var c = 3;
var d = if(a < 10) { b = b + 1; c + 1 }
println(d)
结果是4 也就是将 c+1的结果返回给了d
7 条件和循环案例:
/* if 案例
val age = 34;
if(age < 10) {
println("you are child")
}else{
println("you are adult")
}*/
// 块表达式
/* var a = 1;
var b = 2;
var c = 3;
var d = if(a < 10) { b = b + 1; c + 1 }
println(d)*/ // while 和java使用规则一样
/* var n = 10
while(n>0) {
println(n)
n -= 1
}*/ // for循环 scala只有如下这种形式的for写法
// 1 简易版的for
// var n=10; for(i<- 1 to n) println(i)
//for(c<-"hello world") println(c) // 跳出循环 scala没有类似java的break语句 但可使用 boolean变量 return或Breaks的break函数
/* import scala.util.control.Breaks._
breakable{
var n=10;
for(i<-1 to 10){
if(i==3) {
break;
}
println(i);
}
}*/ // 多重for
/* for(i<-1 to 9; j<-1 to 9){
println(i*j +" " )
}*/
8 定义函数:
定义函数的函数名、参数、函数体,返回值类型, 其中形参和返回值类型都使用 :类型 方式 , 如果函数有返回值 那么需要在形参定义完成后 在使用 = {函数体}
如果定义的函数名和函数体之间没有用 = 关联 那么默认返回值类型是Unit,并且定义的是一个过程而不是一个函数 过程通常用于不需要返回值的函数。
使用 def关键词定义, 注意 参数和函数体之间使用 = 来连接, 如果给默认参数赋初始值 需要在定义形参中里使用 = 赋值
// 代码块中最后一行的返回值就是整个函数的返回值。与Java中不同,不是使用return返回值的。 不过使用 return 我试验了也没发现报错 /*def sayHello(name:String):String ={
"hello " + name
}
var name = sayHello("zm")
println(name)*/
/*def fab(n:Int):Int={
if(n <=1) return 1
else return 3
}
var result = fab(5)
println(result)*/ // 给默认参数赋初始值
/* def sayHello(name:String, age:Int=32) = {
println(name + "| " + age)
}
sayHello("zm",34)
sayHello("zm")*/
9 函数可变参数 + 序列传递 + 递归函数写法
函数定义中 变长参数使用 形参定义后需要增加一个*表示可变参数
object ScalaExample { def main(args: Array[String]): Unit = {
// println(sum(1,2,3)) // 将已有序列直接调用变长参数函数, 需要使用特殊语法让scala解释器识别 ---》 :_*
//var result = sum(1 to 5:_*)
//println(result)
println(sum2( to :_*)) // 1 to 5表示序列 序列传递给可变参数的函数 } // 定义可变参数函数
def sum(nums:Int*)= {
var res = ;
for(num<-nums) {
res += num
}
res
}
// 定义递归函数
def sum2(nums:Int*) :Int={
if(nums.length==)
else nums.head + sum2(nums.tail:_*)
} }
10 过程 lazy值 异常
1 定义函数时,如果函数体直接包裹在了花括号里面,而没有使用=连接,则函数的返回值类型就是Unit。这样的函数就被称之为过程。过程通常用于不需要返回值的函数。
// 过程是函数的一个子集 不需要使用 = 和函数体关联 表示没有返回值的函数
/*def sayHello(name:String){
println("hello: " + name)
}
var result = sayHello("zm")
println(result) // 结果是()*/ // 如果将一个变量生命为lazy //即使文件不存在,也不会报错,只有在第一个使用该变量时如果文件不存在才会报错,证明了表达式计算的lazy特性。
// 这种特性对于特别耗时的计算操作特别有用,比如打开文件进行IO,进行网络IO等
import scala.io.Source._
lazy val lines = fromFile("C://Users//Administrator//Desktop//test.txt").mkString // 异常的写法和Java很类似 例子如下 注意 catch 里面的写法 _: XXException => dosomething
try {
throw new IllegalArgumentException("x should not be negative")
} catch {
case _: IllegalArgumentException => println("Illegal Argument!")
} finally {
print("release resources!")
}
11 数组 和 遍历的集中方式
scala数组底层实际上是Java数组,比如scala的字符串数组在底层就是Java的String[] , 整数数组底层就是Java的Int[]
for遍历几个方式: 增强for循环 正常方式遍历 跳跃遍历 翻转遍历 , 定长变长数组定义和互换和变长数组增减元素写法
// 定长数组 定义定长数组方式1
var a = new Array[Int]()
a() =
// 定义定长数组方式2
var b = Array(,,) // 定义变长数组
import scala.collection.mutable.ArrayBuffer
val b1 = new ArrayBuffer[Int]()
// 使用+=操作符,可以添加一个元素,或者多个元素
b1 +=
b1 += (,,,)
// 使用++=操作符,可以添加其他集合中的所有元素
b1 ++= Array(,,,,)
// for(c<-b1) println(c)
// 删除尾部的几个元素
b1.trimEnd()
// for(c<-b1) println(c)
// 添加元素
// 在index为5的位置上插入数字6
b1.insert(,) // 在index为5的位置上插入数字6
b1.insert(,, , , )// 在index为6的位置上插入数字 7,8,9,10
//for(c<-b1) println(c) // 增强for的遍历
//删除元素SW
b1.remove() // 移除掉index为1上的元素
//for(c<-b1) println(c) // 1 3 4 5 6 7 8 9 10
b1.remove(,) //移除掉index为1上包含index为1开始向后一致移除三个 1 6 7 8 9 10
// for(c<-b1) println(c)
//var d = b1.toArray // 变长数组转换为定长数组
//var c = b.toBuffer // 定长数组转换为变长数组
// 数组普通遍历
// for(i<- 0 until b1.length) println(b1(i))
// for(i<- 0 until (b1.length,2)) println(b1(i)) // 跳跃遍历 间隔两个 取第三个
//for(i<- (0 until b1.length).reverse) println(b1(i)) // 翻转遍历 间隔两个 取第三个
val a = Array(1,2,4,3,5)
val sum = a.sum // 求和
val max = a.max // 获取最大值 // 排序
scala.util.Sorting.quickSort(a)
print(a.mkString(",")) // 获取数组中所有元素内容指定间隔符间隔 1,2,3,4,5
// yield 根据条件选择构建数组
/*
对于for循环的每次迭代,yield都会生成一个将被记住的值。就像有一个你看不见的缓冲区,for循环的每一次迭代都会将另一个新的值添加到该缓冲区
当for循环结束运行时,它将返回所有已赋值的集合。返回的集合的类型与迭代产生的类型相同,因此Map会生成Map,List将生成List,等等。
另外请注意,最初的集合没有改变。for / yield构造根据您指定的算法创建一个新的集合。
* */
// var a = Array(1,2,3,4,5,6)
//var b = for(c<-a) yield c*2
// var b = for(c<-a if c%2==0) yield c*c // yield + for + if 组合筛选构建新数组 //var b = a.filter(_%2==0) // 2-4-6
// var b = a.filter(_%2==0).map(_*2) // 4-8-12 通过数组函数来 筛选和构建新数组
// println(b.mkString("-")) var a = ArrayBuffer(1,2,3,4,5,-8,-3,11,-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)
println(a.mkString("-"))
*/
// 遍历数组里所有元素,当找到第一个负数时 设置flag位 同时标注每个元素如果是大于0下的数组索引位置
/* var firstNagivate = false
var indexFlag = for(i<- 0 until a.length if(!firstNagivate || a(i) > 0)) yield {
if(a(i) < 0) firstNagivate = true
i
}*/
//println(indexFlag.mkString("-"))
/* for(i<- 0 until( indexFlag.length)) { // 将找到元素位置的数据重写到 原来数组中
a(i) = a(indexFlag(i))
}
a.trimEnd(a.length - indexFlag.length) // 将原来数组中不需要的数据截取掉
println(a.mkString("-"))*/
/* println("数组长度为: " + indexFlag.length)
var newA = new Array[Int](indexFlag.length)
for(i<- 0 until( indexFlag.length)) { // 将找到元素位置的数据重写到 新数组中
// newA(i+1) = a(indexFlag(i))
println(i+ " | "+ a(indexFlag(i)))
newA(i) = a(indexFlag(i))
}*/
12 Map 和 Tuple
//map 学习
// 不可变map ()
val ages = Map("zm"->,"liangliang"->)
//ages("zm") = 31 不可以赋值修改
// 可变map
val ages1 = scala.collection.mutable.Map("zm"->,"liangliang"->)
//val ages2 = scala.collection.mutable.Map(("zm",32),("liangliang",31)) 或者这种方式定义
ages1("zm")= // 修改可变map的value值
// 创建空的map
//val ages2 = new mutable.HashMap[String,Int]
//val result = ages1.getOrElse("zm",42); // 获取map的key值
//println(result)
ages1 += ("yan"->,"mei"-> ) // 可变map增加元素
//ages1 -= "yan" // 可变map删除元素
// println(ages1.mkString(","))
/* val ages4 = Map("zm"->32) // 不可变map 增减元素是通过 + - 方式并构建一个新的map接受 可变map增减是通过 += -=方式但必须要构建新的map
val ages5 = ages4 + ("liang"->30)
//println(ages5.mkString(","))
val ages6 = ages5 - "liang"
println(ages6.mkString(","))*/
// map的遍历
//for((k,v)<-ages1) println(k+"," +v)
// val ages6 = for((k,v)<-ages1) yield(v,k) // 使用 yield构建新的map
//println(ages6.mkString(","))
//for(k<-ages1.keySet) println(k)
//for(v<-ages1.values) println(v)
// 对map的key进行排序 看了下 只有immutable包下有这个排序的方法 返回给一个新的map
// val ages7 = scala.collection.immutable.SortedMap("liang"->31,"ping"->29,"ming"->32)
// println(ages7.mkString(","))
//val ages8 = new scala.collection.mutable.LinkedHashMap[String,Int] // 按照插入顺序存放k-v 否则map的k是没有顺序的
//ages8("zm")=34 // 元组 tuple 在spark中有大量的tuple的使用,是一种很灵活的数据结构
val t = ("zm",)
//println(t._1)
val names = Array("zm","ping")
val age1s = Array(,)
val nameages = names.zip(age1s) // zip操作 替代了自定义javabean方式
for ((name, age) <- nameages) println(name + ": " + age)
// tuple ,就是由()包起来,和数据库中一条记录概念类似 ,或者理解为 是一个特殊类型的数组,数组中存储的是不同类型的值,一个元组中最多能存22个元素
var firstTuple = ("str",1,0.5)
println(firstTuple._1) // 返回 str 字符串 注意使用时不要写成按照 数组方式获取值了 这不是数组