Scala基础学习
主要用来处理数据,不处理web,没有类似spring的框架
1. Scala简介
我们基于的scala版本 2.12.10
scala是运行在 JVM 上的多范式(规范)编程语言,同时支持面向对象和面向函数编程。(真实数据与操作过程解耦)
早期scala刚出现的时候,并没有怎么引起重视,随着Spark和Kafka这样基于scala的大数据框架的兴起,scala逐步进入大数据开发者的眼帘。scala的主要优势是它的表达性。
官网地址 http://www.scala-lang.org
2. 为什么要使用scala
- 表达能力强
- 开发大数据应用程序(Spark程序、Flink程序)
- 兼容Java,可以访问的Java类库
- 支持「并发」
3. 安装IDEA的Scala插件
pom文件添加依赖:
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.12.8</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.12</artifactId>
<version>2.4.7</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming_2.12</artifactId>
<version>2.4.7</version>
</dependency>
IDEA默认是不支持scala程序开发,所以需要来安装Scala插件来支持Scala语言。
1. 添加Scala插件后,重启IDEA
2. 需要在project structure --> global libiray 添加scala 2.11.10 依赖(IDE2024没有添加,也可以正常使用)
3. 创建.scala文件
入门案例:
//object: 静态类,这个类里面的所有方法都是静态的,
object demo1 {
def main(args: Array[String]): Unit = {
print("scala测试")
}
}
// 实例的概念
class demo1{
def met1(): Unit = { // Unit代表没有返回的值
}
}
运行结果:
4. Scala中声明变量
语法格式:
val/var 变量名称:变量类型 = 初始值
其中
`val`定义的是**不可重新赋值**的变量(值不可修改) :常量
`var`定义的是**可重新赋值**的变量(值可以修改):变量
val param1:String = "测试scala"
var param2:Int = 100
println(param1)
println(param2)
5. 方法和函数
5.1 方法
语法
def methodName (参数名:参数类型, 参数名:参数类型) : [return type] = {
// 方法体
}
说明
- 参数列表的参数类型不能省略
- 返回值类型可以省略,由scala编译器自动推断
- 返回值可以不写return,默认就是{}块表达式的值
方法的参数
默认参数:在定义方法时可以给参数定义一个默认值。
带名参数:在调用方法时,可以指定参数的名称来进行调用。
def method1(v1:Int, v2: Int)= {
v1 + v2
}
def method2(v1:Int = 12, v2:Int = 13) = { // 可以指定默认值
v1 + v1 + v2
}
def main(args: Array[String]): Unit = {
println(method1(3,5))
println(method2(v2=12, v1=10)) // 可以带变量名赋值
}
运行结果:
注意:如果定义递归方法,不能省略返回值类型
5.2 函数
Scala支持函数式编程,将来编写Spark/Flink程序中,会大量使用到函数
语法
val 函数变量名 = (参数名:参数类型) => 函数体
注意
- 函数是一个变量,长的与方法相似,但不同于方法
- 类似于方法,函数也有输入参数和返回值
- 函数定义不需要使用def定义,而是用val定义
- 无需指定返回值类型
val function1 = (v5:Int) =>{
println(v5)
}
def main(args: Array[String]): Unit = {
function1(8)
}
5.3 case class
1. 创建 case class 和它的伴生 object
2. 实现了 apply 方法让你不需要通过 new 来创建类实例
3. 添加天然的 hashCode、equals 和 toString 方法。由于 == 在 Scala 中总是代表 equals,所以 case class 实例总是可比较的
4. 默认为主构造函数参数列表的所有参数前加 val
case class demo2(v1: Int)
6. 高阶函数
使用函数值作为参数,或者返回值为函数值的“函数”和“方法”,均称之为“高阶函数”
意义:将实际数据,与执行动作进行解耦
7. 函数式编程
理念:数据与动作的解耦
原理:类的实例当做参数传入
我们将来使用Spark/Flink的大量业务代码都会使用到函数式编程
“函数式编程"是一种"编程范式”(programming paradigm)
**函数式编程**是从编程方式(范式)的角度来谈的,可以这样理解:函数式编程把函数当做一等公民,**充分利用函数**、 支持的函数的多种使用方式,主要思想是把运算过程尽量写成一系列嵌套的函数调用
[集合的分类](https://zhuanlan.zhihu.com/p/25512292)
**foreach**
(学会认识方法,要怎么传递参数)
方法描述:接收一个函数对象,函数的输入参数为集合的元素
需要传入一个函数类型A 返回是一个空
foreach(f: (A) => Unit): Unit
示例
// 函数的意义:数据跟动作做解耦
def testForeach(): Unit = {
val list = List(1,2,3,4,5)
val f = (x: Int) => print(x)
list.foreach(f)
// 简便写法
list.foreach((x:Int) => print(x))
list.foreach(x => print(x))
list.foreach(println(_)) // 下划线代表每一个元素
list.foreach(println)
}
**映射 - map**
集合的映射操作是将来在编写Spark/Flink用得最多的操作,是我们必须要掌握的掌握。
方法描述:传入一个函数对象,该函数接收一个类型A,返回值为类型B
def map[B](f: (A) ⇒ B): TraversableOnce[B]
示例
def mapTest(): Unit = {
val list = List(1,2,3,4,5)
val list2: List[String] = list.map((x:Int) => x.toString)
val list3: List[String] = list.map(x => x.toString)
val list4: List[String] = list.map(_.toString)
val list5: List[Int] = list.map(_ + 1)
print(list5)
}
def main(args: Array[String]): Unit = {
mapTest()
}
隐式转换:
通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码
**扁平化映射 - flatmap**
映射扁平化也是将来用得非常多的操作,也是必须要掌握的。
方法描述:[B]最终要转换的集合元素类型,传入一个函数对象,函数的参数是集合的元素,函数的返回值是一个集合
def flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): TraversableOnce[B]
示例 可以理解为读取一行数据
~~~scala
~~~
### **过滤 - filter**
方法描述:传入一个函数对象,接收一个集合类型的参数,返回布尔类型,满足条件返回true, 不满足返回false
```scala
def filter(p: (A) ⇒ Boolean): TraversableOnce[A]
```
方法实操:
~~~scala
~~~
### **排序 - sort**
在scala集合中,可以使用以下几种方式来进行排序
#### sorted默认排序
演示
~~~~scala
~~~~
#### **sortWith自定义排序**
自定义排序,根据一个函数来进行自定义排序
方法描述
~~~scala
def sortWith(lt: (A, A) ⇒ Boolean): List[A]
~~~
方法实操
~~~scala
~~~
**tip:元组**
就是为了操作方便,而给我们提供的一个类型,可以存放不同数据类型在一个元组中。可以理解为可以存放不同类型数据的一个list
### **分组 - groupBy**
我们如果要将数据按照分组来进行统计分析,就需要使用到分组方法,groupBy表示按照函数将列表分成不同的组
方法描述
def groupBy[K](f: (A) ⇒ K): Map[K, List[A]]
方法实操
def groupTest(): Unit = {
val list = List(("jack", 2000), ("tom", 2500), ("tom", 5600))
val res = list.groupBy(_._1).mapValues(_.map(_._2)).map(x => x._1 + x._2.sum)
print(res)
}
def main(args: Array[String]): Unit = {
groupTest()
}
### **聚合 - reduce**
reduce表示将列表,传入一个函数进行聚合计算
方法描述
~~~scala
def reduce[A1 >: A](op: (A1, A1) ⇒ A1): A1
~~~
方法说明
| reduce方法 | API | 说明 |
| ---------- | ----------------- | ------------------------------------------------------------ |
| 泛型 | [A1 >: A] | (下界)A1必须是集合元素类型的子类 |
| 参数 | op: (A1, A1) ⇒ A1 | 传入函数对象,用来不断进行聚合操作<br />第一个A1类型参数为:当前聚合后的变量<br />第二个A1类型参数为:当前要进行聚合的元素 |
| 返回值 | A1 | 列表最终聚合为一个元素 |
scala _ 下划线用法
- 作为“通配符”,类似Java中的*
- 指代一个集合中的每个元素
- 在元组中,可以用方法1, _2, _3访问组员
- 使用模式匹配可以用来获取元组的组员
- 下划线_代表的是某一类型的默认值