一.数据类型概述
看官网: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循环语句
右键basic→New→Scala class:WhileApp
求1+100的和
var num = 1
while (num<=100){
num += 1
//println("==>" +num) //可以一步步打印出来看看执行到了哪一步
}
println(num)
①Step Over一步一步地执行,点一次执行一次
②Step Into往里走,一般用不着
do while
var b =1
do{
b +=1
}while(b<=100)
println(b)
【面试题】:while循环有没有返回值?
答:经测试,没有返回值(或者说返回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循环,当条件满足时才会进入
sum=sum+num
num=num-1
}
println(sum)
var num=0
var sum=0
while(num<=100){ //while循环,当条件满足时才会进入
sum=sum+num
num=num+1
}
println(sum)
while循环中debug操作:
跳出while循环
1.指定某句话打印多少次
var flag=true //flag用来作为一个指示变化的变量的名称,一般设置一个变量flag,是一个来表示判断的变量,当做标志。
var cnt=1 //次数
while(flag){
if(cnt>5){
flag=false
}
println(s"$cnt,冲鸭!!!")
cnt +=1 //每执行一次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循环,所以还要输出一次) 6 flase(cnt 6大于5),输出六次,跳出循环
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是一个左闭右闭的区间
for(i <- 1.until(10)) println(i) //until是一个左闭右开的区间,不包括最后一个
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范围内的奇数-循环守卫
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的平方数-循环返回值
val res=for(i<-1 to 10) yield i*i
println(res)
把abcdef转成大写字母
把abcdef转成大写字母-循环返回值(low)
val result=for(s <- "abcdefg") yield s.toUpper
println(result)
把abcdef转成大写字母-循环返回值(加小写)(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){ //只定义了,不回去执行,需要调用
println(s"fun1.fun2...${a+b}")
}
fun2(100)
}
省略小括号
def three()=1+2
println(three) //没有入参,可以省略小括号
function没有返回值
def sayHello()={ //相当于sayHello():Unit没有返回值
println("你好")
}
四.scala中参数相关概念
(一).默认参数
默认参数在spark中常常出现,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:_*)
五.递归
概念:
递归就是在运行过程中调用自己。只由一种(或多种)简单的基本情况定义的一类对象或方法,并规定其他所有情况都能被还原其基本情况。递归关系就是实体自己和自己建立关系。
对于递归的,一定要手工的加上返回类型。
条件:
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 出现溢出问题了
解决溢出问题—尾递归
@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方法里面和外面有什么区别?
? 答: 只要能访问到都是OK的,但是到后面隐式转换就不然了。