Scala基础知识总结

scala是运行在JVM上的多范式编程语言,同时支持面向对象和面向函数编程。早期,scala刚出现的时候,并没有怎么引起重视,随着Spark和Kafka这样基于scala的大数据框架的兴起,scala逐步进入大数据开发者的眼帘。scala的主要优势是它的表达性。

Scala语言主要用于开发大数据应用程序,如:Spark程序、Flink程序;它具有表达能力强,一行代码抵得上多行java代码,开发速度快;它也兼容Java,可以访问庞大的Java类库,例如:操作mysql、redis、freemarker、activemq等等。

一、环境准备

1 安装

编写scala代码之前,需要先安装scala编译器以及开发工具。Java程序编译执行流程:

在这里插入图片描述

Scala程序编译执行流程:

在这里插入图片描述

scala程序运行需要依赖于Java类库,必须要有Java运行环境,scala才能正确执行。根据上述流程图,要编译运行scala程序,需要:jdk(jvm)scala编译器(scala SDK)

接下来,需要依次安装以下内容:安装JDK安装scala SDK安装IDEA插件

安装JDK

安装JDK 1.8 64位版本,并配置好环境变量

安装scala SDK

scala SDK是scala语言的编译器,要开发scala程序,必须要先安装SDK。本次安装的版本是: 2.11.12;操作步骤:

  1. 下载安装包:链接:https://pan.baidu.com/s/1MLa6TBoMcOZMDVO7SLk1HQ 提取码:moq7
  2. 双击scala-2.11.12.msi,将scala安装在指定目录,例如:D:\scala\
  3. 打开控制台,输入scala -version

安装IDEA scala插件

IDEA默认是不支持scala程序开发,所以需要来安装scala插件来支持scala语言。安装步骤如下:

操作1:查看IDEA的版本号;

操作2:到IDEA官网下载对应版本的IDEA scala插件:http://plugins.jetbrains.com/plugin/1347-scala

注意:务必下载IDEA版本一致的scala插件

操作3:选择配置 > 选择插件;

操作4:点击小齿轮 > 选择从本地安装插件;

操作5:找到下载的插件位置,点击OK;

操作6:重新启动IDEA;

操作7:查看scala插件;

2 解释器

使用scala解释器来学习scala基本语法,scala解释器像Linux命令一样,执行一条代码,马上就可以让我们看到执行结果,用来测试比较方便。

启动scala解释器

要启动scala解释器,只需要以下几步:

  • 按住windows键 + r
  • 输入scala即可

执行scala代码

在scala的命令提示窗口中输入println("hello, world"),回车执行

退出解释器

在scala命令提示窗口中执行:quit,即可退出解释器。

二、基本语法

1 变量

在scala中,可以使用val或者var来定义变量,语法格式如下:

/** val定义:不可重新赋值的变量;var定义:可重新赋值的变量 */
val/var 变量标识:变量类型 = 初始值

[!NOTE]:变量类型写在变量名后面,不需要添加分号,优先使用val定义变量,如果变量需要被重新赋值,才使用var

使用类型推断来定义变量

scala可以自动根据变量的值来自动推断变量的类型。

scala> val name = "tom"
name: String = tom

惰性赋值

在大数据开发中,有时会编写非常复杂的SQL语句,如果直接加载到JVM中,会有很大的内存开销。如何解决?当有一些变量保存的数据较大时,但是不需要马上加载到JVM内存。可以使用惰性赋值来提高效率。语法格式:

lazy val/var 变量名 = 表达式

2 字符串

scala提供多种定义字符串的方式,将来我们可以根据需要来选择最方便的定义方式。

使用双引号

val/var 变量名 = “字符串”

使用插值表达式

scala中,可以使用插值表达式来定义字符串,有效避免大量字符串的拼接。

val/var 变量名 = s"${变量/表达式}字符串"

注意:定义字符串之前添加s;在字符串中,可以使用${}来引用变量或者编写表达式

scala> val name = "zhangsan"
scala> val age = 30
scala> val sex = "male"
scala> val info = s"name=${name}, age=${age}, sex=${sex}"
info: String = name=zhangsan, age=30, sex=male

使用三引号

如果有大段的文本需要保存,就可以使用三引号来定义字符串。例如:保存一大段的SQL语句。三个引号中间的所有字符串都将作为字符串的值。

val/var 变量名 = """字符串1
字符串2"""

3 数据类型&操作符

scala中的类型以及操作符绝大多数和Java一样,以下总结与java不一样的用法:

数据类型

基础类型 类型说明
Byte 8位带符号整数
Short 16位带符号整数
Int 32位带符号整数
Long 64位带符号整数
Char 16位无符号Unicode字符
String Char类型的序列(字符串)
Float 32位单精度浮点数
Double 64位双精度浮点数
Boolean true或false

scala类型与Java的区别:

  1. scala中所有的类型都使用大写字母
  2. 开头整形使用Int而不是Integer;
  3. scala中定义变量可以不写类型,让scala编译器自动推断;

运算符

类别 操作符
算术运算符 +、-、*、/
关系运算符 >、<、==、!=、>=、<=
逻辑运算符 &&、||、!
位运算符 &、||、^、<<、>>
  • scala中没有,++、--运算符

  • 与Java不一样,在scala中,可以直接使用==!=进行比较,它们与equals方法表示一致。而比较两个对象的引用值,使用eq

val str1 = "abc"
val str2 = str1 + ""
str1 == str2
str1.eq(str2)

4 类型层次结构

在这里插入图片描述

类型 说明
Any 所有类型 的父类,,它有两个子类AnyRef与AnyVal
AnyVal 所有数值类型 的父类
AnyRef 所有对象类型(引用类型) 的父类
Unit 表示空,Unit是AnyVal的子类,它只有一个的实例()
它类似于Java中的void,但scala要比Java更加面向对象
Null Null是AnyRef的子类,也就是说它是所有引用类型的子类。它的实例是null
可以将null赋值给任何对象类型
Nothing 所有类型的子类
不能直接创建该类型实例,某个方法抛出异常时,返回的就是Nothing类型,因为Nothing是所有类的子类,那么它可以赋值为任何类型

nothing

def main(args: Array[String]): Unit = {
   
    val c = m3(1,0)
}

def m3(x:Int, y:Int):Int = {
   
    if(y == 0) throw new Exception("这是一个异常")
    x / y
}

问题:以下代码是否有问题?

val b:Int = null

scala会解释报错:Null类型并不能转换为Int类型,说明Null类型并不是Int类型的子类

5 条件表达式

条件表达式就是if表达式,if表达式可以根据给定的条件是否满足,根据条件的结果(真或假)决定执行对应的操作。scala条件表达式的语法和Java一样。

有返回值的if

与Java不一样的是:1、条件表达式也是有返回值的;2、没有三元表达式,可以使用if表达式替代三元表达式

scala> val sex = "male"
sex: String = male

scala> val result = if(sex == "male") 1 else 0
result: Int = 1

块表达式

scala中,使用{}表示一个块表达式,和if表达式一样,块表达式也是有值的,值就是最后一个表达式的值。

scala> val a = {
   
    | println("1 + 1")
    | 1 + 1
	}

6 循环

在scala中,可以使用for和while,但一般推荐使用for表达式,因为for表达式语法更简洁

6.1 for表达式
for(i <- 表达式/数组/集合) {
   
    // 表达式
}
scala> val nums = 1.to(10)                                                              
nums: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 

scala> for(i <- nums) println(i)
//简写方式:
scala> for(i <- 1 to 10) println(i)

嵌套循环

for(i <- 1 to 3; j <- 1 to 5) {
   print("*");if(j == 5) println("")}

守卫

for表达式中,可以添加if判断语句,这个if判断就称之为守卫。我们可以使用守卫让for表达式更简洁。

for(i <- 表达式/数组/集合 if 表达式) {
   
    // 表达式
}

示例:使用for表达式打印1-10之间能够整除3的数字

// 添加守卫,打印能够整除3的数字
for(i <- 1 to 10 if i % 3 == 0) println(i)

for推导式

将来可以使用for推导式生成一个新的集合(一组数据),在for循环体中,可以使用yield表达式构建出一个集合,把使用yield的for表达式称之为推导式.

示例:生成一个10、20、30…100的集合

// for推导式:for表达式中以yield开始,该for表达式会构建出一个集合
val v = for(i <- 1 to 10) yield i * 10
6.2 while循环

scala中while循环和Java中是一致的

scala> var i = 1
scala> while(i <= 10) {
   
     | println(i)
     | i = i+1
     | }

7 break和continue

在scala中,类似Java和C++的break/continue关键字被移除了;如果一定要使用break/continue,就需要使用scala.util.control包的Break类的breablebreak方法。

break用法

导入Breaks包import scala.util.control.Breaks._;使用breakable将for表达式包起来;for表达式中需要退出循环的地方,添加break()方法调用。示例如下:

// 导入scala.util.control包下的Break
import scala.util.control.Breaks._

breakable{
   
    for(i <- 1 to 100) {
   
        if(i >= 50) break()
        else println(i)
    }
}

continue用法

continue的实现与break类似,但有一点不同:实现break是用breakable{}将整个for表达式包起来,而实现continue是用breakable{}将for表达式的循环体包含起来就可以了。示例如下:

// 导入scala.util.control包下的Break    
import scala.util.control.Breaks._

for(i <- 1 to 100 ) {
   
    breakable{
   
        if(i % 10 == 0) break()
        else println(i)
    }
}

8 方法

def methodName (参数名:参数类型, 参数名:参数类型) : [return type] = {
   
    // 方法体:一系列的代码
}

注意:参数列表的参数类型不能省略;返回值类型可以省略,由scala编译器自动推断;返回值可以不写return,默认就是{}块表达式的值。

scala> def add(a:Int, b:Int) = a + b
m1: (x: Int, y: Int)Int

scala> add(1,2)
res10: Int = 3

返回值类型推断

scala定义方法可以省略返回值,由scala自动推断返回值类型。这样方法定义后更加简洁。但是要注意:定义递归方法,不能省略返回值类型。示例如下:

scala> def m2(x:Int) = {
   
     | if(x<=1) 1
     | else m2(x-1) * x
     | }
<console>:13: error: recursive method m2 needs result type
       else m2(x-1) * x
1.1 方法参数

scala中的方法参数,使用比较灵活。它支持以下几种类型的参数:

默认参数:在定义方法时可以给参数定义一个默认值。

// x,y带有默认值为0 
def add(x:Int = 0, y:Int = 0) = x + y
add()

带名参数:在调用方法时,可以指定参数的名称来进行调用。

def add(x:Int = 0, y:Int = 0) = x + y
add(x=1)

变长参数:如果方法的参数是不固定的,在参数类型后面加一个*号,表示参数可以是0个或者多个。

def 方法名(参数名:参数类型*):返回值类型 = {
   
    方法体
}
scala> def add(num:Int*) = num.sum
add: (num: Int*)Int

scala> add(1,2,3,4,5)
res1: Int = 15
1.2 调用方式

在scala中,有以下几种方法调用方式:

后缀调用法:与Java没有区别。

对象名.方法名(参数)
scala> Math.abs(-1)
res3: Int = 1

中缀调用法

对象名 方法名 参数
scala> Math abs -1
res4: Int = 1

操作符即方法:在scala中,+ - * / %等这些操作符和Java一样,但在scala中:所有的操作符都是方法,操作符是一个方法名字是符号的方法

花括号调用法:方法只有一个参数,才能使用花括号调用法

Math.abs{
    
    // 表达式1
    // 表达式2
}
scala> Math.abs{
   -10}
res13: Int = 10

无括号调用法:如果方法没有参数,可以省略方法名后面的括号

def m3()=println("hello")
m3

9 函数

scala支持函数式编程,函数定义不需要使用,无需指定返回值类型;def定义语法如下:

val 函数变量名 = (参数名:参数类型, 参数名:参数类型....) => 函数体
scala> val add = (x:Int, y:Int) => x + y
add: (Int, Int) => Int = <function2>

scala> add(1,2)
res3: Int = 3

方法和函数的区别:

  1. 方法是隶属于类或者对象的,在运行时,它是加载到JVM的方法区中
  2. 可以将函数对象赋值给一个变量,在运行时,它是加载到JVM的堆内存中
  3. 函数是一个对象,继承自FunctionN,函数对象有apply,curried,toString,tupled这些方法。方法则没有

示例:方法无法赋值给变量

scala> def add(x:Int,y:Int)=x+y
add: (x: Int, y: Int)Int

scala> val a = add
<console>:12: error: missing argument list for method add
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `add _` or `add(_,_)` instead of `add`.
       val a = add

方法转换为函数

有时候需要将方法转换为函数,作为变量传递,就需要将方法转换为函数;使用_即可将方法转换为函数。

scala> def add(x:Int,y:Int)=x+y
add: (x: Int, y: Int)Int

scala> val a = add _
a: (Int, Int) => Int = <function2>

10 数组

scala中数组的概念是和Java类似,可以用数组来存放一组数据。scala中,有两种数组,一种是定长数组,另一种是变长数组

1.1 定长数组

定长数组指的是数组的长度不允许改变的,数组的元素可以改变的。语法如下:

// 通过指定长度定义数组
val/var 变量名 = new Array[元素类型](数组长度)

// 用元素直接初始化数组
val/var 变量名 = Array(元素1, 元素2, 元素3...)

注意:在scala中,数组的泛型使用[]来指定,使用()来获取元素

scala> val a = new Array[Int](100)
a: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...)

scala> a(0) = 110

scala> a(0)
110
1.2 变长数组

变长数组指的是数组的长度是可变的,可以往数组中添加、删除元素。

定义变长数组

创建变长数组,需要提前导入ArrayBuffer类import scala.collection.mutable.ArrayBuffer,语法:

  • 创建空的ArrayBuffer变长数组:

    val/var a = ArrayBuffer[元素类型]()
    
    val a = ArrayBuffer[Int]()
    
  • 创建带有初始元素的ArrayBuffer

    val/var a = ArrayBuffer(元素1,元素2,元素3....)
    
    scala> val a = ArrayBuffer("hadoop", "storm", "spark")
    a: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer(hadoop, storm, spark)
    

添加/修改/删除元素

  • 使用+=添加元素
  • 使用-=删除元素
  • 使用++=追加一个数组到变长数组
// 定义变长数组
scala> val a = ArrayBuffer("hadoop", "spark", "flink")
a: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer(hadoop, spark, flink)

// 追加一个元素
scala> a += "flume"
res10: a.type = ArrayBuffer(hadoop, spark, flink, flume)

// 删除一个元素
scala> a -= "hadoop"
res11: a.type = ArrayBuffer(spark, flink, flume)

// 追加一个数组
scala> a ++= Array("hive", "sqoop")
res12: a.type = ArrayBuffer(spark, flink, flume, hive, sqoop)
1.3 遍历数组

可以使用以下两种方式来遍历数组:

  • 使用for表达式直接遍历数组中的元素

    scala> val a = Array(1,2,3,4,5)
    scala> for(i<-a) println(i)
    
  • 使用索引遍历数组中的元素

    scala> val a = Array(1,2,3,4,5)
    scala> for(i <- 0 to a.length - 1) println(a(i))
    scala> for(i <- 0 until a.length) println(a(i))
    

0 until n——生成一系列的数字,包含0,不包含n

0 to n ——包含0,也包含n

1.4 数组常用操作

scala中的数组封装了一些常用的计算操作,在对数据处理的时候不需要再重新实现;以下为常用的几个算法:

求和:数组中的sum方法可以将所有的元素进行累加,然后得到结果

scala> val a = Array(1,2,3,4)
scala> a.sum

最大值:数组中的max方法,可以获取到数组中的最大的那个元素值

scala> val a = Array(4,1,2,4,10)
scala> a.max

最小值:数组的min方法,可以获取到数组中最小的那个元素值

scala> val a = Array(4,1,2,4,10)
scala> a.min

排序sorted方法,将数组进行升序排序;reverse方法,将数组进行反转,实现降序排序

scala> val a = Array(4,1,2,4,10)
scala> a.sorted
scala> a.sorted.reverse

11 元组

元组可以用来包含一组不同类型的值。例如:姓名,年龄,性别,出生年月。元组的元素是不可变的。语法定义:

  1. 使用括号来定义元组

    val/var 元组 = (元素1, 元素2, 元素3....)
    
  2. 使用箭头来定义元组(元组只有两个元素)

    val/var 元组 = 元素1->元素2
    
scala> val a = ("zhangsan", 20)
scala> val a = "zhangsan" -> 20

访问元组

使用_1、_2、_3…来访问元组中的元素,_1表示访问第一个元素,依次类推.

scala> val a = "zhangsan" -> "male"
scala> a._1
scala> a._2

12 List

列表是scala中最重要的、也是最常用的数据结构。List具备以下性质:可以保存重复的值,有先后顺序。在scala中,也有两种列表,一种是不可变列表、另一种是可变列表。

1.1 不可变列表

不可变列表就是列表的元素、长度都是不可变的。使用List(元素1, 元素2, 元素3, ...)来创建一个不可变列表,语法格式:

val/var 变量名 = List(元素1, 元素2, 元素3...)

使用Nil创建一个不可变的空列表

val/var 变量名 = Nil

使用::方法创建一个不可变列表

val/var 变量名 = 元素1 :: 元素2 :: Nil

注意:使用::拼接方式来创建列表,必须在最后添加一个Nil

/* 示例一:创建一个不可变列表,存放以下几个元素(1,2,3,4)*/
scala> val a = List(1,2,3,4)
/* 示例二:使用Nil创建一个不可变的空列表 */
scala> val a = Nil
/* 示例三:使用::方法创建列表,包含-2、-1两个元素 */
scala> val a = -2 :: -1 :: Nil
1.2 可变列表

可变列表就是列表的元素、长度都是可变的。

要使用可变列表,先要导入import scala.collection.mutable.ListBuffer

注意:可变集合都在mutable包中,不可变集合都在immutable包中(默认导入)

使用ListBuffer[元素类型]()创建空的可变列表,语法结构:

val/var 变量名 = ListBuffer[Int]()

使用ListBuffer(元素1, 元素2, 元素3...)创建可变列表,语法结构:

val/var 变量名 = ListBuffer(元素1,元素2,元素3...)
/* 示例一:创建空的整形可变列表 */
scala> val a = ListBuffer[Int]()
/* 示例二:创建一个可变列表,包含以下元素:1,2,3,4 */
scala> val a = ListBuffer(1,2,3,4)

可变列表操作

// 导入可变列表
scala> import scala.collection.mutable.ListBuffer
// 创建可变列表
scala> val a = ListBuffer(1,2,3)
// 获取第一个元素
scala> a(0)
// 追加一个元素
scala> a += 4
// 追加一个列表
scala> a ++= List(5,6,7)
// 删除元素
scala> a -= 7
// 转换为不可变列表
scala> a.toList
// 转换为数组
scala> a.toArray
1.3 列表的常用操作

判断列表是否为空

scala> val a = List(1,2,3,4)
scala> a.isEmpty

拼接两个列表

scala> val a = List(1,2,3)
scala> val b = List(4,5,6)
scala> a ++ b

获取列表的首个元素和剩余部分

scala> val a = List(1,2,3)
scala> a.head
scala> a.tail

反转列表

scala> val a = List(1,2,3)
scala> a.reverse

获取列表前缀和后缀

scala> val a = List(1,2,3,4,5)
scala> a.take(3)
scala> a.drop(3)

扁平化(压平)

扁平化表示将列表中的列表中的所有元素放到一个列表中。

在这里插入图片描述

scala> val a = List(List(1,2), List(3), List(4,5))
scala> a.flatten

拉链与拉开

  • 拉链zip:使用zip将两个列表,组合成一个元素为元组的列表
  • 拉开unzip:将一个包含元组的列表,解开成包含两个列表的元组
scala> val a = List("zhangsan", "lisi", "wangwu")
scala> val b = List(19, 20, 21)
scala> a.zip(b)
scala> res1.unzip

转换字符串

toString方法可以返回List中的所有元素

scala> val a = List(1,2,3,4)
scala> println(a.toString)

生成字符串

mkString方法,可以将元素以分隔符拼接起来。默认没有分隔符

scala> val a = List(1,2,3,4)
scala> a.mkString
scala> a.mkString(":")

并集

union表示对两个列表取并集,不去重

scala> val a1 = List(1,2,3,4)
scala> val a2 = List(3,4,5,6)
// 并集操作
scala> a1.union(a2)
// 可以调用distinct去重
scala> a1.union(a2).distinct

交集

intersect表示对两个列表取交集

scala> val a1 = List(1
  • 2
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

栖溪阁晓生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值