一.數據類型概述
看官網:DOCUMENTION→Tour of Scala→Unified Types
Unified Types | Tour of Scala | Scala Documentation (scala-lang.org)
(一).類型的基本概念
Any是最頂層,也叫超類型或頂級類型,它下面有一個值類型AnyVal和一個引用類型AnyRef。
值類型AnyVal包括Double、Float、Long、Int、Short、Byte、Unit、Boolean、Char類型;
引用類型AnyRef包括List、Option、YourClass。
Nothing是最底層,也叫底部類型。
任意一種類型都有一個子類:Nothing
整型
整型的默認類型是Int
Byte: -128-127
Short:-32768-32767
Int 整型的默認類型
Long(使用Long類型,在數字后面加上L)
整型可以分為有符號類型(+、-)和無符號類型(只能存非負數)
練習:
1.報錯type mismatch是因為類型不匹配
2.報錯integer number too large是因為超出了范圍
浮點類型
浮點類型的默認類型是Double
Float:32位,單精度(使用Float類型末尾加F)
Double:64位,雙精度(使用Double類型末尾加D)
使用Float類型小數點太長的話會導致精度丟失。
Char類型
使用Char類型用單引號擴起來即可。
c1.toInt 將c1轉換成Int類型(a的ascall碼值為97;b的ascall碼值為98;)
Boolean類型
true? ?0
false? 1
val flag:Boolean = true 返回:flag:Boolean = true
val flag:Boolean = false 返回:flag:Boolean = false
補充知識
println()輸出
1. \t 制表符
2. \n 制列符
3. \\ 轉譯符
(二).類型轉換
精度低的類型往精度高的轉換(越往右邊精度越高)
判斷某數值的類型
小技巧:記不住代碼的時候可以按“Tab”鍵補齊。
10.isInstanceOf[Int] #判斷10是否為Int類型
10.0.isInstanceOf[Int] #判斷10.0是否為Int類型
10.0.asInstanceOf[Int] #把10.0轉換為Int類型
(三).字符串操作
單行字符串操作
右鍵basic→New→Scala class:TypeApp
val money = 67850
println("輸出:"+money)
printf ("%d",money)? //%d:代表10進制
println()
printf("%f", math.Pi)? //%f:代表float類型
println()
printf("%s %f %d", "abc", 1.6, 4)? //%s代表String字符串類型
附:println(text:String,xs:Any*) Unit 其中xs:Any*代表前面的“xs”所有類型都可以
val name = "PK"
?val age = 32
掌握這種但是不建議:
?val info = "name="+name+",age="+age
println(info)??
建議使用字符串插值:
val info = s"name=$name,age=$age" //s是固定的寫法,用$直接引用就好了
println(info)
上述操作可以直接println(s"name=$name,age=${age-1}")? //用{}做帶運算的,【注意】只要是這種樣式,一進s“”里面,在$前面加{}就對了。
多行字符串操作““””
常用于多行mysql的輸入輸出
val welcome =
? ? ? """
? ? ? ? |歡迎來到若澤大數據
? ? ? ? |這里是未來
? ? ? ? |我是006-武漢-阿坤
? ? ? ? |""".stripMargin
? ? println(welcome)
例1:
var sql=
? """
? ? |select e.empno,e.ename,e.deptno,d.dname
? ? |from
? ? |emp e join dept d
? ? |on e.deptno=d.deptno
? ? |""".stripMargin
? ? println(sql)
例2:
var day="20211122"
? ? println(
? ? ? s"""
? ? ? ? |select * from xxx where day='$day'
? ? ? ? |""".stripMargin)
(四).運算符
1.pom文件加spark-core依賴(Project→target→pom.xml點開)
【注】:pom文件導入包依賴,可參考:pom文件導入maven依賴 - 簡書 (jianshu.com)
添加:
<dependency>
? ? <groupId>org.apache.spark</groupId>
? ? <artifactId>spark-core-2.12</artifactId>
? ? <version>3.1.1</version>
</dependency>
2.IDEA如何找源碼? 點擊右上角放大鏡,然后輸入需要的文件名,比如SparkContext.scala
字符串操作
scala> 10/3? 返回res24:Int =3? //相當于除后取整數
scala> a=10/3? 返回a:Int =3
scala> a:Double=10/3? 返回a:Double =3.0? //Int類型/Int類型結果Int類型,最后轉成Double類型
scala>val a:Double=10.0/3? 返回a:Double =3.333333333333335
scala>a.formatted("%.3f")? 返回res25:String=3.333? //%.3f取三位小數→%.nf取n位小數
scala>10%3? 返回res27:Int=1? //10對3取模(取余)
二.Scala語句
(一).if語句
scala中沒有swhich語句
右鍵basic→New→Scala class:IfApp
if單分支
val num = 10
if(num % 2 == 0){
println(s"$num 是偶數")
}
if雙分支
val num = 10
if(num % 2 == 0){
? ? ? println(s"$num 是偶數")
? ? }else{
? ? ? println(s"$num 是奇數")
? ? }
if多分支
val score = StdIn.readInt()
? ? if(score==100){
? ? ? println("滿分,牛啊牛啊")
? ? }else if (score>80 && score<100){
? ? ? println("還可以,加油")
? ? }else if (score>60 && score<=80){
? ? ? println("還行吧")
? ? }else {
? ? ? println("小菜雞")
? ? }
求兩個數的最大值
【注】命名:駝峰標識,即命名兩個或兩個以上單詞放在一起的時候,每個單詞的第一個字母大寫
val a=10
? ? val b=20
?var result=Int.MinValue? //求最大值這里放最小值;求最小值這里放最大值
? ? if (a>b){
? ? ? result=a
? ? }else {
? ? ? result=b
? ? }
? ? println(s"最大值是:$result")
上述操作太繁瑣了,可以直接這樣:
val a=10
? ? val b=20
?val maxNumber = if(a>b) a else b
? ?println(s"最大值是 $maxNumber")
? ? }
正常寫法:
val a=10
? ? val b=20
val maxNumber = if (a>b) {
? ? a}else {
? ? ? b}
? ? ? println(s"最大值是 $maxNumber")
? ? }? //在scala中,如果{}里面只有一行,那么{}可以省略,但是建議一定要把{}加上
if語句套用if語句
val group=StdIn.readChar()
? ? if (group=='1'){
? ? ? print("你是一組的。。。")
? ? }else{
? ? ? println("你不是一組的。。")
? ? ? println("請輸入成績")
? ? ? var score =StdIn.readDouble()
? ? ? if(score>=99){
? ? ? ? println("牛啊牛啊")
? ? ? }else{
? ? ? ? println("去玩泥巴吧!")
}
(二).while循環(huán)語句
右鍵basic→New→Scala class:WhileApp
求1+100的和
var num = 1
? ? while (num<=100){
? ? ? num += 1
? ? ? //println("==>" +num)? //可以一步步打印出來看看執(zhí)行到了哪一步
? ? }
? ? println(num)

①Step Over一步一步地執(zhí)行,點一次執(zhí)行一次
②Step Into往里走,一般用不著
do while
var b =1
? ? do{
? ? ? b +=1
? ? }while(b<=100)
? ? println(b)
【面試題】:while循環(huán)有沒有返回值?
答:經測試,沒有返回值(或者說返回Unit值)
測試:
var c=1
? ? val res=while (c<=100){
? ? ? c +=1
? ? }
? ? println(res)
此時返回:()[空,代表沒有]
var c=1
? ? val res:Unit=while (c<=100){? //Unit:沒有值,相當于java中的void;Unit類型只有一個值()
? ? ? c +=1
? ? }
? ? println(res)
求1+2+3+...+99+100的和
var num=100
? ? var sum=0
? ? while(num>100){??//while循環(huán),當條件滿足時才會進入
? ? ? sum=sum+num
? ? ? num=num-1
? ? }
? ? println(sum)
var num=0
? ? var sum=0
? ? while(num<=100){? //while循環(huán),當條件滿足時才會進入
? ? ? sum=sum+num
? ? ? num=num+1
? ? }
? ? println(sum)
while循環(huán)中debug操作:
跳出while循環(huán)
1.指定某句話打印多少次
var flag=true? //flag用來作為一個指示變化的變量的名稱,一般設置一個變量flag,是一個來表示判斷的變量,當做標志。
? ? var cnt=1? ? //次數
? ? while(flag){
? ? ? if(cnt>5){
? ? ? ? flag=false
? ? ? }
? ? ? println(s"$cnt,沖鴨?。?!")
? ? ? cnt +=1? //每執(zhí)行一次cnt+1
? ? }
上述操作雖然是cnt > 5但實際輸出了六次,具體過程如下:
①cnt 1 > 5? 1 true(cnt 1不大于5)
②cnt 2 > 5? 2 true(cnt 2不大于5)
③cnt 3 > 5? 3 true(cnt 3不大于5)
④cnt 4 > 5? 4 true(cnt 4不大于5)
⑤cnt 5 > 5? 5 true(cnt 5不大于5)
⑥cnt 6 > 5(此時已經進了while循環(huán),所以還要輸出一次)? 6 flase(cnt 6大于5),輸出六次,跳出循環(huán)
2.遍歷10以內的數,==5時結束
var n = 1
? ? breakable {
? ? ? while(n < 10) {
? ? ? ? println("n =====" + n)
? ? ? ? n += 1
? ? ? ? if(n == 5) {
? ? ? ? ? break()
? ? ? ? }
? ? ? }
? ? }
println("exit")
此時返回:
n ===== 1
n ===== 2
n ===== 3
n ===== 4
exit
3.輸出10以內的奇數,跳過偶數
var n=0
? ? while(n<10){
? ? ? breakable{
? ? ? ? n += 1
? ? ? ? if(n % 2 !=0){
? ? ? ? ? println(n)
? ? ? ? }else{
? ? ? ? ? break()
? ? ? ? }
? ? ? }
? ? }
? ? println("exit")
此時返回:
1 3 5 7 9
exit
手動導包:上述2、3中最開始break和breakable都是紅色報錯字體,自動導包不可以的話需要手動導包:在package和object之間輸入import scala.util.control.Breaks._
(三).for語句
右鍵basic→New→Scala class:WhileApp
val a="abc"
? ? for (c <- a){? //把a里面每一個都賦給c
? ? ? println(c)
? ? }
for(i <- 1 to 10) println(i)? //把1-10里面每個東西賦值給i
等價于for(i <- 1.to(10)) println(i)? //to是一個左閉右閉的區(qū)間
for(i <- 1.until(10)) println(i)? //until是一個左閉右開的區(qū)間,不包括最后一個
for(i <- 1.to(10,2)) println(i)? //把1-10里面每個東西按步長為2賦值給i(復制到IDEA里面去可以查看to的源碼)
等價于for(i <- 1.to(10) by 2) println(i)
for(i <- 1.to(10) reverse) println(i)? //倒序輸出
等價于for(i <- 1 10 to 1 by -1) println(i)? //倒序且按步長為1輸出
Range (1,10) 實際上就是Range 1 until 10
Range (1,10,2) 實際上就是inexact Rage 1 until 10 by 2(其中2是步長step,步長不能為0)
輸出1到100范圍內的奇數
輸出1到100范圍內的奇數-普通方式
for(i <- 1 to 100){
? ? if(i % 2 ==1){
? ? ? println(i)
? ? }
? ? }
輸出1到100范圍內的奇數-循環(huán)守衛(wèi)
for(i<- 1 to 100 if i % 2 ==1){
? ? ? println(i)
? ? ? }
輸出1到10且不為3
for(i<- 1 to 10 if i !=3){
println(i)
}
計算1到10的平方數
計算1到10的平方數-普通方式
for(i<- 1 to 10){
? ? ? println(i*i)
? ? }
計算1到10的平方數-循環(huán)返回值
val res=for(i<-1 to 10) yield i*i
? ? println(res)
把abcdef轉成大寫字母
把abcdef轉成大寫字母-循環(huán)返回值(low)
val result=for(s <- "abcdefg") yield s.toUpper
? ? println(result)
把abcdef轉成大寫字母-循環(huán)返回值(加小寫)(low)
val result=for(s <- "abcdefg") yield s.toString.toUpperCase+s
? ? println(result)
把abcdef轉成大寫字母-高階函數,函數式編程
"abcdefg".map(x => x.toString.toUpperCase()+x).foreach(println) //非常重要,生產上常用
三.function的定義與使用
function的引入:
val a=10
? val b=20
?val op = "-"
? ?if(op == "+"){
? ? println(a+b)
? ?}else if(op == "-"){? //java中要使用equals;scala中可以不用equals,直接使用“==”
? ? println(a-b)
這樣的操作太過于繁瑣冗余,代碼的復用性太低了,想辦法把a,b,op傳給compute:compute(a,b,op),此時引入function:
def 函數名/方法名(x:Int,y:Int):Int={?
? ?if(x>y) x else y? //求最大最小值
} //函數和方法不是同一個東西喲;(x:Int,y:Int)代表入參;Int代表返回值類型;有返回值用“=”
{}里面的叫做方法體,是不可以缺少的
①方法體的最后一行是作為整個方法的返回值的,不需要用return;
②方法體只有一行時,可以省略{}
③scala中,如果function沒有入參的話,()都可以省略
function簡單入門
簡單加法
def add(a:Int,b:Int):Int={
? ? ? a+b
? ? }
?println(add(2, 4))
省略花括號
def three()=1+2
function嵌套使用
?def fun1(a:Int){
? ? ?def fun2(b:Int){? //只定義了,不回去執(zhí)行,需要調用
? ? ?println(s"fun1.fun2...${a+b}")??
? ? }
? ? ?fun2(100)
? }
省略小括號
def three()=1+2
? println(three)? //沒有入參,可以省略小括號
function沒有返回值
def sayHello()={? //相當于sayHello():Unit沒有返回值
? ? println("你好")
? }
四.scala中參數相關概念
(一).默認參數
默認參數在spark中常常出現(xiàn),spark中配置是有一個全局配置,默認在一個配置文件spark-default.conf中,spark-default.conf是一個自定義的配置文件。
生產場景:
def loadConf(conf:String="spark-default.conf"):Unit={
println(conf)
loadConf()? //這里會默認調用spark-default.conf
如果直接loadConf("spark-default.conf") ,就直接調用這個了
實例:
def sayHello(name:String): Unit ={? //(name:String)這里可以放一個值進去作為默認值,也可以不放,后面再輸入一下,比如下面的“LK”
? ? ? ?println(s"Hello:$name")
? ?}
def sayHello(name:String="若澤"): Unit ={
? ? ? ?println(s"Hello:$name")
? ?}
(二).參數命名*
命名參數:按名稱命名傳遞(傳遞時不安坐標傳遞,而是按照名稱傳遞的)
調用:println(speed(100,10))? //太low了
println(speed(100,10))
調用: println(speed(time=10,distance=100)) //命名參數
(三).可變參數
例1:求很多數的和
def sum(nums: Int*):Int={? //Int*表示可以傳入n個Int的值,一定要放在參數的最后一位喲
? ?var res=0
? for(num <- nums){
? ? ? res+=num
? ? }
? ?res
?}
?def sum(nums: Int*):Int={
? ? var res=0
? ? ? for(num <- nums){
? ? ? res+=num
? ?}
? ?res
? ?}
?println(sum(1 to 10:_*))? //1 to 10:_*表示將1to10轉變成可變參數(將某個字段轉變成可變參數加“:_*”),這里把1 to 10理解為一個集合,把這個集合轉變成可變參數
例2
def printInfo(students:String*)={
? ? ? students.foreach(println) //foreach實際上把每個都編譯一下
? ? }
? printInfo("001","002","003")
def printInfo(students:String*)={
? ? ? students.foreach(println)
? ? }
? ? val array=Array("001","002","003")
? ? printInfo(array:_*)
五.遞歸
概念:
遞歸就是在運行過程中調用自己。只由一種(或多種)簡單的基本情況定義的一類對象或方法,并規(guī)定其他所有情況都能被還原其基本情況。遞歸關系就是實體自己和自己建立關系。
對于遞歸的,一定要手工的加上返回類型。
條件:
? ? ?1. 子問題須與原始問題為同樣的事,且更為簡單;
? ? ?2. 不能無限制地調用本身,須有個出口,化簡為非遞歸狀況處理。
例題:求階乘
def factorial(n:Long):Long={
?if (n==1) 1
? ?else n*factorial(n-1)
? }
?println(factorial(10))
}
def factorial(n:Long):Long={
? if (n==1) 1
? ? else n*factorial(n-1)
?}
?println(factorial(100000))
經典報錯:Exception in thread "main" java.lang.StackOverflowError? 出現(xiàn)溢出問題了
解決溢出問題—尾遞歸
? @tailrec
? ? def factorial2(n:Int, acc:BigInt):BigInt={ //acc聚合累加器
? ? ? if(n==1) acc? //如果等于1,調用自己
? ? ? else factorial2(n-1,n*acc)
? ? }
? ? println(factorial2(100000,acc=1))
思考題:函數在main方法里面和外面有什么區(qū)別?
?? 答: 只要能訪問到都是OK的,但是到后面隱式轉換就不然了。