Scala语言的特点
Scala是一门以java虚拟机(JVM)为运行环境并将面向对象和函数式编程的最佳特性结合在一起的静态类型编程语言
1) Scala是一门多范式的编程语言, Scala支持面向对象和函数式编程
2) Scala源代码(.scala)会被编译成java字节码(.class) , 然后运行于JVM之上,并可以调用现有的Java类库,实现两种语言的无缝对接.
3) scala是源于java,也将函数式编程语言的特点融合到java中
Scala基础
//静态对象: 里面定义的方法就是静态方法,定义的变量就是静态变量(不用加static关键字)
object HelloScala {
def main(args: Array[String]): Unit = {
//使用val定义的变量值是不可变的,相当于java里用final修饰的变量
val i = 1
//使用var定义的变量是可变的,在scala中鼓励使用val
var s = "hello
//scala编译器会自动推断变量的类型,必要的时候可以指定类型
//变量名在前,类型在后
val str: String = "world"
}
}
调用方法
scala中的= - * / %等操作符的作用于java一样,为运算符& | ^ >> <<也一样 只是有一点特别:这些操作符实际上是方法, 列如
a.+(b) 简写为 a+ b a方法可以写成 a.方法(b)
定义方法
定义方法用def关键字 m1是方法名称 x和y是参数列表 Int为返回值类型 x*y为方法体
scala> def m1(x:Int , y:Int) :Int = x * y
m1: (x: Int, y: Int)Int
数组
1. 定长数组(Array) 不定长数组(ArrayBuffer) toBuffer数组转化为数组缓冲 reverse数组反转
package cn.doit.com.demo2
import scala.collection.mutable.ArrayBuffer
/*
Array: 定长数组,长度不可变,地址值不可变,但是内容可变
ArrayBuffer: 可变数组,长度可变,内容可变
*/
object ArrayTest {
def main(args: Array[String]): Unit = {
//初始化一个长度为8的定长数组,其所有元素均为0
val arr1 = new Array[Int](8)
//直接打印定长数组,内容为数组的hashcode值
println(arr1)
//将数组转化成数组缓冲,就可以看到原数组中的内容了
//toBuffer会将数组转换成数组缓冲
println(arr1.toBuffer)
//注意: 如果new,相当于调用了数组的apply方法,直接为数组复制
//初始化一个长度为1的定长数组
val arr2 = Array[Int](10)
println(arr2.toBuffer)
println(arr2.toBuffer.reverse)
/*
---------------------------------------------------------------------
*/
val ab = ArrayBuffer[Int]()
//向数组缓冲的尾部追加一个元素
// +=尾部追加元素
ab += 1
//追加多个元素
ab += (2,3,4,5) //元组
//追加一个数组
ab ++= Array(6,7)
//追加一个数组缓冲
ab ++= ArrayBuffer(8,9)
//在数组某个位置插入元素用insert
//索引0的位置追加-1和0
ab.insert(0,-1,0)
println(ab)
//删除数组某个位置的元素用remove
//删除从索引8位置开始删除2个
ab.remove(8,2)
println(ab)
}
}
2. 遍历数组for 数组排序方法sorted
package cn.doit.com.demo1
/*
1.增强for循环
2.好用的until会生成角标,0 until 10包含0不包含10
*/
object ForDemo {
def main(args: Array[String]): Unit = {
var str = Array(abcdef)
//取出字符串对应的脚本的字符
val c = str(0)
//增强for
for(s <- str) println(s)
//取出字符串对应的角标 [0,6]的有序区间
for(s <- 0 to 5) println(s)
//方法不好 to包括开头也包括结尾
for(s <- 0 to str.length-1) println(str(s))
//until 包括开始不包括结尾
for(s <- 0 until str.length) println(str(s))
//reverse是将前面生成的Range反转
for(s <- (0 until str.length).reverse) println(str(s))
//数组排序 sorted
val sorted = str.sorted
println(sorted)
}
}
Yield
package cn.doit.com.demo1
/*
for循环中的yield会把当前的元素记录下来,保存在集合中,循环结束后返回该集合
scala中for循环是有返回值的 如果被循环的是Map,返回的就是Map,被循环的是
List,返回的就是List
*/
object Yield {
def main(args: Array[String]): Unit = {
var str = Array(1,24,6,8,9)
var a = for(s <- str) yield s*10
println(a.toBuffer)
}
}
映射
在 Scala中,把哈希表这种数据结构叫做映射 getOrElse() 判断是否有这个值,没有返回个默认值
package cn.doit.com.demo2
import scala.collection.mutable.Map
/*
Map映射
在scala中,有两种Map,一个是immutable包下的Map,该Map中的内容不可变;
另一个是mutable包下的Map,该Map中的内容可变
*/
object MapDemo {
def main(args: Array[String]): Unit = {
//第一种创建map映射方法 val定义的scores变量意味着变量的引用不变
//但是Map中的内容可变
val scores = Map("tom"->20 , "jerry"->30 , "kitty"->25)
println(scores)
//第二种创建map映射方法, ->可省略
val scores2 = Map("tom"->20 , "jerry"->30 , "kitty"->25)
println(scores2)
//获取映射中的值
val i = scores("jerry")
//修改Map中的内容
scores("tom") = 18
//追加元素
scores += ("kitty"->99 , "city" -> 22)
println(i)
//修改映射中的值,如果映射中有值,返回映射中的值,
//没有就返回默认值
scores.getOrElse("city" , 0)
println(scores)
}
}
元组 长度和内容都不可改变
映射是K/V对偶的集合 , 对偶是元组的最简单形式 , 元组可以装着多个不同类型的值 toMap对偶集合转化成Map映射
package cn.doit.com.demo2
object YuanZu {
def main(args: Array[String]): Unit = {
//定义元组时用小括号将多个元素包起来,元素之间用逗号分隔
//元素的类型可以不一样,元素个数可以任意多个
val t = ("laowang" , 3.14 , 10)
/*
获取元组中的元素可以使用下划线加角标,但是需要注意的是元组的角标
从1开始的
*/
println(t._1)
println(t._2)
println(t._3)
//将对偶的集合转化成映射
val arr = Array(("tom",88) , ("jerry",95))
//toMap可以将对偶的集合转化成映射
val map = arr.toMap
println(map)
}
}
集合
Scala的集合有三大类: 序列Seq 集合Set 映射Map , 所有的集合都扩展自Iterable特质
在Scala中集合有可变(mutable)和不可变(immutable)两种类型,immutable类型的集合
初始化后就不能改变了(注意与val修饰的变量进行区别)
1. Set集合
1.1 不可变set
package cn.doit.com.demo2
/*
immutable.Set
scala中导入的set是不可变的Set , set中的内容和长度都不可以改变
不可变的set只能读取数据, 不能修改
*/
object SetDemo1 {
def main(args: Array[String]): Unit = {
//Set无序 去重,不可追加删除 参数只读
val a = Set(1,2,3,4,5,4,3,2,1)
println(a)
//可以获取数组的长度
println(a.size)
//判断一个元素是否存在
// val bool = a.contains(5)
// println(bool)
val bool1 = a(5)
println(bool1)
//遍历数组
for (elem <- a) {
println(elem)
}
}
}
1.2 可变set contains() 查看元素是否存在
package cn.doit.com.demo2
import scala.collection.mutable
object SetDemo2 {
def main(args: Array[String]): Unit = {
//可变set 无序 去重 长度可变 内容可变
var mu = mutable.Set(1,2,3,4,6,8,1)
//可以追加数据
mu += 10
println(mu)
//可以移除数据
mu -= 10
println(mu)
//查看元素是否存在
val bool = mu.contains(3)
println(bool)
//可以获取数组的长度
println(mu.size)
//遍历
for (elem <- mu) {
println(elem)
}
}
}
2. Map集合
Map是集合 map为做映射,是个方法 foreach也是相当于for循环,但是foreach不返回一个新的集合
package cn.doit.com.demo1
import scala.collection.mutable
object MapDemo {
def main(args: Array[String]): Unit = {
val map1 = new mutable.HashMap[String , Int]()
//向map中添加数据
map1("spark")=1
map1 += (("hadoop" , 2))
map1.put("storm",3)
println(map1)
//从map中移除元素
map1 -= "spark"
map1.remove("hadoop")
println(map1)
}
}
union并集 intersect交集 diff差集
package cn.doit.com.demo2
object SetDemo3 {
def main(args: Array[String]): Unit = {
val s1 = Set(1, 2, 3, 4, 5)
val s2 = Set(4, 5, 6, 7, 8)
//求并集
val s3 = s1 union s2
println(s3)
//求交集
val s4 = s1.intersect(s2)
println(s4)
//求差集
// var temp = s1
// for (elem <- s4) {
// temp = temp - elem
// }
// println(temp)
val s5 = s1.diff(s2)
println(s5)
}
}
flatMap切分压平 sortBy集合排序
函数的定义 =>函数的标志
简写形式: val func: = (x:Int , y:Int) => x + y
极简写法: arr.map( _ * 10) _代表数据类型,类型要一致
正式写法: val func:(Int ,Int) => Int = ( x , y ) => x + y func:后面为参数类型 Int为返回值类型 x,y相当于形参
filter 过滤
package cn.doit.com.demo3
object mapDemo {
def main(args: Array[String]): Unit = {
val arr = Array(1,2,3,4,5,6,7,8,9,10)
//定义一个函数
val a = (x: Int) => x*10
//map是做映射 将Array数组的值一一映射到函数里执行代码
//map是一个方法,参数是一个函数,内部进行for循环
val ints = arr.map(a)
println(ints.toBuffer) //ArrayBuffer(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
//简写
val ints1 = arr.map((x: Int) => x * 100)
println(ints1.toBuffer)
//再次简写 参数类型也可以省略
val ints2 = arr.map((x) => x * 100)
println(ints2.toBuffer)
//如果是一个参数,小括号也可以省略
val ints3 = arr.map(x => x * 100)
println(ints3.toBuffer)
//filter动词,是一个方法,进行过滤,满足函数条件执行
val f = (x: Int) => x % 2 != 0
val f2 = arr.filter(f)
println(f2.toBuffer)
}
}
函数的深入理解
package cn.doit.com.day03.demo06
object FuncInDeep {
//函数本质就是一个引用类型,函数就可以作为参数传入到方法中,也可以作为方法的返回值
val func = (x: Int, y: Double) => x + y
//完整写法
val func2: (Int, Double) => Double = (x: Int, y: Double) => x + y
/*
真正函数定义的方式
几个参数就是使用Function几
两个参数Function2 三个参数Function3
*/
//参数一参数二为参数类型 , 参数三位返回值类型
val func3 = new Function2[Int, Double, Double] {
//重写Function2的方法 函数默认发方法是apply方法
override def apply(v1: Int, v2: Double): Double = v1 + v2
}
//使用语法糖简写
val func4 = new ((Int, Double) => Double) {
//重写Function2的方法 函数默认发方法是apply方法
override def apply(v1: Int, v2: Double): Double = v1 + v2
}
def main(args: Array[String]): Unit = {
val res: Double = func3(1, 2.5)
}
}
小案例 求每个单词出现的个数
package cn.doit.com.demo2
object WordCount {
def main(args: Array[String]): Unit = {
val lines = Array("spark,hadoop,Flink,spark", "Spark,flink,spark,hadoop", "spark,flink,hive")
//切分压平
val words: Array[String] = lines.flatMap(e => e.split(","))
//Map(hadoop -> ArrayBuffer(hadoop, hadoop), spark -> ArrayBuffer(spark, spark, Spark, spark, spark), flink -> ArrayBuffer(Flink, flink, flink), hive -> ArrayBuffer(hive))
//将数据变小写分组
val grouped: Map[String, Array[String]] = words.groupBy(x => x.toLowerCase)
//进行计数
val wordAndCount: Map[String, Int] = grouped.map(t => (t._1, t._2.length))
//排序
val sorted: List[(String, Int)] = wordAndCount.toList.sortBy(t => -t._2)
//打印
println(sorted)
}
}
}