Scala基础语法
1.基本规范
1. 通常一行一条命令,末尾无需添加分号。
2.一行包含多条命令,两两之间用分号隔开,建议非特殊语法不允许主动这样写代码。
3.可以在过程中【导包】,过程中定义函数,也可以在Object外部【导包】。
2.基本语法
必知点
一:scala中的下划线( _ )
**1、**详细讲解:
=> 下划线(_)在scala中是占位符,可以表示【任意内容】
**2、**应用场景:
import package._ 相当于 java * 【导包】
case _ 相当于 default 【模拟匹配】
**3、**基于下划线的简易传参语法:
//参数占位符,参数列表中每个参数可以使用一条下划线
def cal(func:(Int,Int)=>Int,a:Int*)={
var sum = 0
for (elem <- a) {
sum = func(sum,elem)
}
sum
}
// 下面两种写法的效果相同
val rst = cal(_ + _, 1, 2, 3, 4, 5)
val rst = cal((a,b)=>a+b, 1, 2, 3, 4, 5)
二:元组 TupleN
基本规则
基本格式:TupleN[T1,T2,T3,...]
讲解:
N:1~22,表示能存放数量 => 最多可放22个
T:泛型
举例:
Tuple2("java", 80)
元组类型的表达:
推荐写法:syntactic suger 语法糖
(String,Int) <=> Tuple2[String,Int]
注意事项:为避免冲突,需说明括号()的表示
() 可表示:
1.元组 val tuple2 = ("java",88)
2.数组下标提取 array(0)
3.方法的参数列表 method(p1,...,pn)
一:二元组的声明与初始化
val tuple2 = ("java",88) // 实际应用:最简语法 ✔
val tuple2: (String, Int) = ("java", 88) // 初学推荐写法 ✔
val tuple2: Tuple2[String, Int] = Tuple2("java", 88) //完整学法
二:元组的使用
元组值的获取
val tuple2: (String, Int) = Tuple2("java", 88)
val value1 = tuple2._1 // 获取元组第一个值
val value2 = tuple2._2 // 获取元组第二个值
println(s"${value1} ${value2}")
----------------------------------------
java 88
----------------------------------------
迭代器遍历
val tp = (1,"good",12.34f,true)
val iterator: Iterator[Any] = tp.productIterator //迭代器
iterator.foreach(println)
----------------------------------------
1
good
12.34
true
----------------------------------------
三:Option[T] 【常见】
1.使用
val opt:Option[T] = ...
val rst = opt.getOrElse(default:T)
得到的两个值:默认值【没有】或者有效值【有】
2.设计
None extends Option
Some extends Option
3.案例
def add(a:Int,b:Int):Option[Int] = {
val sum = a + b
if(sum>100){
None
}else{
Some(sum)
}
}
val opt1: Option[Int] = add(65, 55)
val rst2: Int = opt1.getOrElse(-1)
println(rst2)
--------------------------------
-1
--------------------------------
1、变量与常量
变量
一:基本格式
var 变量名[:数据类型] = 值
二:特别说明
**1、**创建变量:必须赋初值。
2、可以不指定变量的具体类型,如 var a = 5,则变量的类型由【首次】赋值的值【类型】决定且锁定。
3、若声明时已指定变量类型,如 var a:String = “hello” ,则类型不可更改。
常量
一:基本格式
//创建常量且初始化后,常量的类型和值都将锁定,不可更改
val 变量名[:数据类型] = 值
二:特别说明
**=>**创建常量且初始化后,常量的类型和值都将锁定,不可更改。
2、数据类型
2.1类型体系
Scala当中,总体的体系呈现“菱形”分布。
类型体系图的解读:
1、Any是所有类型的父类,Nothing是所有类型的子类。
2、在基本类型【AnyVal】中,主要有以下类型:
Unit(≈void),Boolean,Byte,Short,Int,Long,
Float,Double,BigInt,BigDecimal
3、在引用类型【AnyRef】中,主要有以下类型:
String,集合(List,Map,Set...),数组,自定义类,对象....
2.3类型别名
一:基本格式
type 别名 = 类型Type
二:案例
type t = String
var str:t = "hello world!"
println(str)
-------------------------------
hello world!
-------------------------------
三:特别说明
类型别名的主要作用:简化复杂的类型名称。
【一般情况下不建议使用】
3、运算符
赋值运算符: = += -= *= /= %=
算术运算符: + - * / % 【没有 ++ --】
关系运算符: > >= < <= == !=
逻辑运算符: && || !
3.1运算符重载
从语法上来说scala是没有运算符的。Scala的运算符实际上是方法名,如1 + 2实际上就是1.+(2)。我们可以将之视为运算符,是因为在Scala中,如果方法的参数小于等于1个的话,那么“.”和括号就都是可选的。
案例:val str = obj + param 等同于 val str = obj.+(param…)。
4、程序逻辑
4.1表达式
一:在Scala中一切皆为表达式
//【声明时】就会执行,即:无论如何都会将{}内的内容输出来
var b[:Int] = {
println("initialize variable b")
5*5
}
println(b)
----------------------------------
initialize variable b
25
----------------------------------
二:惰性表达式:特殊的表达式。
//【使用时】才会执行,即:只有在使用时,才会将{}内的内容输出来
var a = 5
lazy val c ={
println("initialize variable c")
a*Math.PI
}
println(c)
三:中置表达式
注意点:方法的参数【只有一个参数】才可以使用中置表达式
1:左右闭
基本语法
// >= START && <= END
val NAME = START to END [by STEP] // STEP缺省默认增值为1
案例
// >=1 && <=10
val range = 1 to 10
2:左闭右开
基本语法
// >= START && < END
val NAME = START until END [by STEP] // STEP缺省默认增值为1
案例
// >=1 && <10
val range = 1 until 10
4.2分支
一:基本语法
if...else if...else...
二:案例
//格式化:s"" raw"" f""
val age = 15
if (age >= 18){
//${}中的{}用于锁定边界
println(s"你已经>=${age},成年了")
}else{
println(s"还未成年,你才$age")
}
4.3类三元运算
一:基本语法
val str = if(条件) "..." else "..."
二:案例
val age = 12
val str = if(age>=18) "成年" else "未成年"
println(str)
----------------------
未成年
----------------------
4.4循环
一:while循环
var i = 1
while (i<=3){
println(i)
i+=1
}
----------------------
1
2
3
----------------------
二:do while循环
var i = 1
do {
println(i)
i+=1
}while(i<=3)
----------------------
1
2
3
----------------------
三:for循环
总体的应用:for循环主要面向于集合。
基本使用案例
1、range中默认增值为1
// 1 <= range <= 3
val range = 1 to 3
for (e <- range){
println(e)
}
----------------------
1
2
3
----------------------
2、改变range中默认的增值,此处将增值改为3
val range = 1 to 10 by 3
for (e <- range){
println(e)
}
----------------------
1
4
7
10
----------------------
3、其余计算(减,乘…),此处案例:能被3整除的数
val range = 1 to 10
for (e <- range;if (e%3==0)){
println(e)
}
----------------------
3
6
9
----------------------
四:模式匹配(类似于switch…catch)【重点】
一:基本格式
val result = someValue match {
case 模式1 => ... //处理模式1的情况
case 模式2 => ... //处理模式2的情况
//更多模式匹配
}
【注意点】:需要提取的内容用变量,不需要提取内容用占位符(_)占位
二:典型应用场景
数值
val number = Random.nextInt(4)
val rst = number match {
case 0 => "余额"
case 1 => "充值"
case 2 => "活动"
case 3 => "贷款"
case _ => "未知"
}
println(s"$number => $rst")
------------------------
1 => 充值
------------------------
条件守卫
val age = Random.nextInt(100)
val rst = age match {
case a if a<7 => "幼年"
case a if a<18 => "少年"
case a if a<30 => "青年"
case a if a<60 => "壮年"
case _ => "老年"
}
println(s"${age} belongs to ${rst}")
------------------------
20 belongs to 青年
------------------------
字符串+条件守卫
val content = "aa@qq.com"
val rst = content match {
case a if a.matches("^\\w+@[0-9a-z]{2,}\\.(com|cn|org)$" ) => "邮箱"
case a if a.matches("^1[3-9]\\d{9}$" ) => "手机号"
case a if a.matches("^\\d{17}[0-9X]$" ) => "PID"
case _ => "RUBBISH"
}
println(s"$content $rst")
------------------------
aa@qq.com 邮箱
------------------------
元组
val tp2 = (5,101)
//需要提取的内容用变量,不需要提取内容用占位符(_)占位
val rst = tp2 match {
case (3,_) => (3,1)
case (5,a) => if(a%2==0) (5,0) else (5,1)
case _ => (0,0)
}
println(rst)
------------------------
(5,1)
------------------------
列表
val tp3:Any = List(1,"100")
val rst = tp3 match {
case List(1,_) => "ONE"
case List(2,_) => "TWO"
case List(3,_) => "THREE"
case _ => "NULL"
}
println(rst)
------------------------
ONE
------------------------
嵌套
val tp3:Any = (1,("java",67))
val rst = tp3 match {
case (1,(sub:String,score:Int)) => (sub,score)
case _ => ("UnknownFormat",1)
}
println(rst)
------------------------
(java,67)
------------------------
识别值的类型
val v:Any = 1
val rst = v match {
case a:Int => f"${Math.PI*Math.pow(a,2)}%.2f"
case a:String => "String"
case a:Boolean => a.toString
case _ => "unknown"
}
println(rst)
------------------------
3.14
------------------------
5、集合
必知点
1.【导包】(可变集合包 与 不可变集合包)
面向大数据时,通常使用的是不可变集合包
// immutable:不可变集合包 mutable:可变集合包
import scala.collection.immutable.Set // 导入具体类
import scala.collection.mutable._ // 导入包内所有类
import scala.collection.mutable.{ListBuffer,ArrayBuffer} // 导入包内部分类
注意:【默认】导入的是【不可变集合包】。
若要导入可变集合包,基本步骤如下(以导入Set为例)
1.先导入
import scala.collection.mutable
2.再使用
val set = mutable.Set()
2.【泛型】
=>泛型一般用中括号表示:[T1,…,TN]
5.2集合的基本操作
一:分组操作(以list为例)
grouped:连续3个为一组
val list = List(1,2,3,4,5,6,7,8)
val iterator: Iterator[List[Int]] = list.grouped(3)
iterator.foreach(println)
----------------------
List(1, 2, 3)
List(4, 5, 6)
List(7, 8)
----------------------
sliding:滑动窗口=>连续3个为一组,下一组需要跳过2个数后再开始。
val list = List(1,2,3,4,5,6,7,8)
val iterator: Iterator[List[Int]] = list.sliding(3, 2)
iterator.foreach(println)
----------------------
List(1, 2, 3)
List(3, 4, 5)
List(5, 6, 7)
List(7, 8)
----------------------
combinations:以3个元素作为一个基本单位进行排列组合操作,不考虑顺序问题。
val list = List(1,2,3,4)
val iterator: Iterator[List[Int]] = list.combinations(3)
iterator.foreach(println)
----------------------
List(1, 2, 3)
List(1, 2, 4)
List(1, 3, 4)
List(2, 3, 4)
----------------------
groupBy:【e的计算式子(如:e%2…)得出的值】作为键,【e本身】作为值。
应用一:
val list = List(1,2,3,4,5,6,7,8)
val map: Map[Int, List[Int]] = list.groupBy(e => e % 2)
map.foreach(println)
----------------------
(1,List(1, 3, 5, 7))
(0,List(2, 4, 6, 8))
----------------------
应用二:
val list = List(1,2,3,4,5,6,7,8)
val map: Map[String, List[Int]] = list.groupBy(e => if (e <= 4) "小于4" else "大于4")
map.foreach(println)
----------------------
(小于4,List(1, 2, 3, 4))
(大于4,List(5, 6, 7, 8))
----------------------
二:交集& 并集| 差集&~(以Set为例,Set无序不重复)
【Scala支持运算符的重载】
1.交集:intersect 或 &
完整语法:
val intersect: Set[Int] = set1.intersect(set2)
简化语法:✔
val union: Set[Int] = set1 & set2
案例:
val set1 = Set(1,2,89,3,71)
val set2 = Set(1,51,2,3,17)
val intersect: Set[Int] = set1 & set2
println(intersect)
----------------------
Set(1, 2, 3)
----------------------
2.并集:union 或 |
完整语法:
val union: Set[Int] = set1.union(set2)
简化语法:✔
val union: Set[Int] = set1 | set2
案例:
val set1 = Set(1,2,89,3,71)
val set2 = Set(1,51,2,3,17)
val union: Set[Int] = set1 | set2
println(union)
----------------------
Set(89, 1, 2, 17, 71, 3, 51)
----------------------
3.差集:diff 或 &~
完整语法:
val diff: Set[Int] = set1.diff(set2)
简化语法:✔
val union: Set[Int] = set1 &~ set2
案例:
val set1 = Set(1,2,89,3,71)
val set2 = Set(1,51,2,3,17)
// set1 相对于 set2 的差集
val diff: Set[Int] = set1 &~ set2
println(diff)
----------------------
Set(89, 71)
----------------------
强调说明:差集最终的结果类型【取决于】diff左侧元素的类型。若set1为可变集合,set2为不可变集合,则set1.diff(set2)最终的结果为可变的集合。
三:集合的添加与删除操作(以Map为例)
需知知识点——图解
1.可变集合
A.声明Map集合(可变集合)
val map:mutable.Map[String,Int] = mutable.Map.empty
B.map添加操作
在一个map容器中进行添加操作
//单个添加
map += (("java",88))
//多个添加
map ++= (Array(("scala",98),("hadoop",84)))
map2.foreach(println)
----------------------
(hadoop,84)
(scala,98)
(java,88)
----------------------
C.map删除操作
//将map2容器中的 java 删除
map2 -= "java"
map2.foreach(println)
----------------------
(hadoop,84)
(scala,98)
----------------------
2.不可变集合
A.声明Map集合(不可变集合)
val map = Map.empty
B.map添加操作
在另一个map集合中保留原来内容同时进行添加操作
// 将map容器中内容 + 新添的两个内容 存放于 map2容器中
val map2: Map[String, Int] = map ++ Map(("html", 11),("java", 23))
map2.foreach(println)
----------------------
(html,11)
(java,23)
----------------------
C.map删除操作
val map4: Map[String, Int] = map2.-("html")
map4.foreach(println)
----------------------
(java,23)
----------------------