一、Scala的介绍
在线学习文档:https://www.runoob.com/scala/scala-tutorial.html
1、Scala是基于Java的语言,必须安装jdk,scala语言也是运行在jvm虚拟机中的。2、Scala语言是大数据中重要的开发语言重要程度大于Java。是开发Spakr以及Flink的重要语言。3、Scala语言表达能力强,一行代码抵得上Java多行,开发速度快。4、Scala名字由来:Scalable Language两个单词相结合;意大利语中“scala”意为“梯子”或“楼梯”5、Scala之父Martin Odersky(马丁·奥德斯基)6、Scala的编程思想参照函数式编程(函数式编程非常的重要)7、关于版本 2.12.8- Spark 2.x 使用Scala 2.11预构建,除了版本2.4是用Scala 2.12预构建的。- Spark 3.0+使用Scala 2.12预构建,删除2.11。- Kafka 2.5.0弃用对Scala 2.11的支持- 本课程采用2.12.88、Scala 是一个符合函数式编程的思想(函数在这个里面是一等公民)9、scala文件,会被scalac 这个工具编译为.class文件,jvm运行.class文件,不是javac编译的。
二、环境的安装
1、必须安装jdk ,我们使用的版本是jdk 1.8 版本。
2、下载scala安装包。
3、安装 scala-2.12.8.msi
4、配置环境变量
先找到你的scala的安装目录,配置SCALA_HOME

5、scala -version
6、简单使用一下,进入scala编辑器,输入scala即可进入
输入:quit 退出编辑。
三、与IDEA的整合
在idea中安装插件,我们选择离线安装:
选择磁盘上的 scala-intellij-bin-2021.3.20.zip


查看IDEA的版本是多少对应的插件。
四、如何在idea中编写scala代码
1、创建mavan项目
2、在pom.xml中导入scala的开发包
<dependencies><dependency><groupId>org.scala-lang</groupId><artifactId>scala-library</artifactId><version>2.12.8</version></dependency></dependencies>
3、在src\main 下 创建一个文件夹scala
4、添加scala的支持

5、创建一个类,运行一个hello world!
6、创建一个类
选择Object,不要选class也不要选Case Object
编写代码,右键运行:
object _01基础语法 {def main(args: Array[String]): Unit = {println("hello world");}}
五、Scala的基础语法
1、变量
/*** @Author laoyan* @Description TODO* @Date 2022/4/28 11:24* @Version 1.0*/object _02变量 {def main(args: Array[String]): Unit = {/*** java 中声明* int a = 0;* 在scala中 使用 val 或者 var 来定义变量* 格式如下:* var/val 变量名:变量的类型 = 初始值* var : 可以修改值* val : 它修饰的变量,不能再次赋值 ,类似于Java 的final*/var a:Int = 0;val b:Int = 10;a = 100;// b = 200;/*** 在scala 中,可以省略 ;* 可以省略 数据类型,scala 会根据我们的值推导出我们的 变量的类型*/var c = 100val name:String = "张三"val name2 = "张三"println(name)println(c)// 优先使用 val ,如果定义的变量确实需要修改 它的值,这个时候再考虑使用var// lazy 惰性赋值/*语法: lazy val/var 变量名= 变量值使用lazy修饰的变量,一般是不加载到jvm中的,只有后面使用到了这个变量才会去加载这个值。这样的好处是:不浪费jvm资源。一般适用于该变量对应的值非常的大,比如是一个大数组,大集合,大语句等*/lazy val sql = "此处是一个非常长的SQL语句"println(sql)}}
2、字符串
/**
* @Author laoyan
* @Description TODO
* @Date 2022/4/28 11:46
* @Version 1.0
*/
object _03字符串 {
/**
* Scala中的字符串
* 可以使用:
* 双引号
* 插值表达式
* 三引号
*
*/
def main(args: Array[String]): Unit = {
var message = "五一放假三天"
val name= "张三"
val age = 10
// 插值表达式 以 s开头 ,后面跟上双引号,引号中可以使用${key}
var msg01 = s"name=${name},age=${age}"
var msg02 = "name="+name+",age="+age;
println(msg01);
println(msg02);
val sql = "select * from user where age >=10";
val sql2 = """select * from
| user
| where age >=10""".stripMargin
// 不加这个stripMargin ,我们语句中 | 前面的格式也会被输出的。
val sql3 = """select * from
| user
| where age >=10"""
println(sql)
println(sql2)
println(sql3)
}
}
3、数据类型

我们观察到scala中的数据类型都是首字母大写的,它没有Integer ,它有Int
# Any是所有类型的父类
它定义了一些通用的方法如equals、hashCode和toString。Any有两个直接子类:AnyVal和AnyRef。
# AnyVal是所有值类型的父类
有9个预定义的非空的值类型分别是:Double、Float、Long、Int、Short、Byte、Char、Unit和Boolean。Unit是不带任何意义的值类型,它仅有一个实例可以像这样声明:()。所有的函数必须有返回,所以说有时候Unit也是有用的返回类型。
# AnyRef是所有引用类型的父类
AnyRef代表引用类型。所有非值类型都被定义为引用类型。在Scala中,每个用户自定义的类型都是AnyRef的子类型。如果Scala被应用在Java的运行环境中,AnyRef相当于java.lang.Object。
# Nothing是所有类型的子类
Nothing是所有类型的子类,也是Null的子类,他没有一个具体的实例对象,常见的应用如:抛出异常、程序exit,无限循环等,返回值为Nothing类型。
Nothing没有对象,但是可以用来定义类型。例如,如果一个方法抛出异常,则异常的返回值类型就是Nothing(虽然不会返回) 。
def get(x:Int):Int = {
if(x < 0) throw new Exception(...) //返回值类型Nothing
else ....
}
# Null是所有引用类型的子类
Null只有一个实例对象null,主要用来和其他的JVM语言进行互操作,但是几乎不应该在Scala代码中使用。
| 类型 | 说明 |
|---|---|
| Any | 所有类型的父类,,它有两个子类AnyRef与AnyVal |
| AnyVal | 所有数值类型的父类 |
| AnyRef | 所有对象类型(引用类型)的父类 |
| Unit | 表示空,Unit是AnyVal的子类,它只有一个的实例{% em %}() {% endem %} 它类似于Java中的void,但scala要比Java更加面向对象 |
| Null | Null是AnyRef的子类,也就是说它是所有引用类型的子类。它的实例是{% em %}null{% endem %} 可以将null赋值给任何对象类型 |
| Nothing | 所有类型的子类 不能直接创建该类型实例,某个方法抛出异常时,返回的就是Nothing类型,因为Nothing是所有类的子类,那么它可以赋值为任何类型 |
4、运算符

补充:
scala中没有 ++ -- 运算符
跟java不一样的还有,在scala中,== 以及 != ,他们跟 equals 效果是一样的,比较的是值。
如果想比较两个对象的引用是否一致 用 eq.
/**
* @Author laoyan
* @Description TODO
* @Date 2022/4/28 14:36
* @Version 1.0
*/
object _05运算符 {
def main(args: Array[String]): Unit = {
val str1 = "abc"
val str2 = str1 + ""
println(str1 == str2) //true 跟Java不一样的地方,== 比较的是值
println(str1.equals(str2)) //true 比较的是值
println(str1.eq(str2)) //false 比较的是内存地址
}
}
5、条件表达式(if else)
跟Java不一样的是,条件表达式是有返回值的。
在scala中,没有三元表达式,可以使用if 表达式代替三元(三目)
/**
* @Author laoyan
* @Description TODO
* @Date 2022/4/28 14:42
* @Version 1.0
*/
object _06条件表达式 {
def main(args: Array[String]): Unit = {
val sex = "男"
// if 是有返回值的,默认是最后一句话 就是返回值
// 如果最后是打印语句 ()
val abc = if(sex == "男"){
println("这是个男滴")
1
}else{
println("这是个女滴")
0
}
println(abc)
// if 是 有返回值的
val result = if(sex == "男") 1 else 0
println(result)
// 块表达式 放在一个 {} 里面的就是块
val a = {
println("老闫着怒火赛")
1 + 1
}
println(a) // 2
// 解释: 块表达式的最后一句就是 返回值
}
}
6、循环之for循环
/**
* @Author laoyan
* @Description TODO
* @Date 2022/4/28 14:52
* @Version 1.0
*/
object _07循环 {
def main(args: Array[String]): Unit = {
// scala 中 有两种循环方式 for while
// 一般推荐使用for循环,因为简单
/**
* for (i <- 表达式/数组/集合) {
* // 语句
* }
*/
// 循环打印 1 到 100
for(i <- 1 to 100){
println(i)
}
val arr = 1.to(100)
for(i <- arr){
println(i)
}
}
}
嵌套循环:
/**
* @Author laoyan
* @Description TODO
* @Date 2022/4/28 15:00
* @Version 1.0
*/
object _08嵌套循环 {
def main(args: Array[String]): Unit = {
/*
*****
*****
*****
*/
/**
* 分析:
* 1、for循环 3次,每一次换行
* 2、里面的for 控制 打印 5 个 *
*/
for(i <- 1 to 3){
for(i <- 1 to 5){
print("*")
}
println()
}
}
}
for循环的守卫
/**
* @Author laoyan
* @Description TODO
* @Date 2022/4/28 15:03
* @Version 1.0
*/
object _09for循环中的守卫 {
def main(args: Array[String]): Unit = {
// 在for 循环的条件 内,添加了 if 条件,这个条件称之为守卫
for(i <- 1 to 10){
if(i % 3 == 0){
println(i)
}
}
// 守卫的写法
for(i <- 1 to 10 if i % 3 == 0){
println(i)
}
}
}
for循环的推导式
/**
* @Author laoyan
* @Description TODO
* @Date 2022/4/28 15:07
* @Version 1.0
*/
object _10for循环的推导式 {
/**
* 通过yield + for 循环构建一个集合 ,这个就是成为 for循环的推导式
* 使用for循环的推导式可以生成一个新的 集合 (一组数据)
*
*/
def main(args: Array[String]): Unit = {
// 生成一个 10,20,30,40... 100 的集合
val list = for(i <- 1 to 10) yield i * 10;
for(i <- list){
println(i)
}
}
}
7、while循环
/**
* @Author laoyan
* @Description TODO
* @Date 2022/4/28 15:15
* @Version 1.0
*/
object _11While循环 {
// 这个跟Java用法一样
def main(args: Array[String]): Unit = {
var i = 1
while(i <= 10){
println(i)
i = i + 1
}
}
}
8、关于break 以及 continue
import scala.util.control.Breaks._
/**
* @Author laoyan
* @Description TODO
* @Date 2022/4/28 15:18
* @Version 1.0
*/
object _12break以及continue {
// scala 中没有标准的 break 以及 continue 这样的关键字
// 如果一定要这个效果的话
// break :终止当前的循环 ,进入下一个循环
// continue : 终止本次的循环,进入下一次循环
// 需要使用scala.util.control包的Break类的breakable和break方法
def main(args: Array[String]): Unit = {
// 想实现break效果
// 步骤: 1、导入包scala.util.control.Break._
// 2、使用breakable 将整个for循环包裹起来
// 3、在for循环需要退出的地方,调用break() 方法
// 使用for表达式打印1-100的数字,如果数字到达50,退出for表达式
breakable{
for(i <- 1 to 100){
println(i)
if(i == 50 ) break()
}
}
// 实现continue 效果
/**
* 基本上跟 break 步骤一样,唯一的区别是
* 实现break是用breakable{}将整个for表达式包起来,
* 而实现continue是用breakable{}将for表达式的循环体包含起来就可以了
*/
// 打印1-100的数字,使用for表达式来遍历,如果数字能整除10,不打印
for(i <- 1 to 100){
breakable{
if(i % 10 ==0 ) break()
println(i)
}
}
}
}
9、方法
方法的定义(语法):
def methodName (参数名:参数类型, 参数名:参数类型) : [return type] = {
// 方法体:一系列的代码
}
1、参数列表中的参数类型不能省略
2、返回值类型可以省略
3、返回值可以不写return ,一般都是那方法体中的最后一句的值作为返回值
4、如果是递归方法,返回值不能省
/**
* @Author laoyan
* @Description TODO
* @Date 2022/4/28 15:36
* @Version 1.0
*/
object _13方法 {
/**
*
* 定义个方法,让两个值相加
*/
def add(a: Int, b: Int): Int = {
return a + b;
}
def add2(a: Int, b: Int) = {
a + b;
}
// 定义一个递归方法
def jiecheng(num:Int):Int = {
if(num ==1){
1;
}else {
num * jiecheng(num-1);
}
}
def main(args: Array[String]): Unit = {
println(add(2,3))
// 求某个值的阶乘 10! =10 * 9 * 8 * 7 *6 *5 ... * 1
// 10! = 10 * 9!
println(jiecheng(10));
}
}
方法的参数:
在scala中方法的参数非常灵活:
- 默认参数
- 带名参数
变长参数 ```scala /**
- @Author laoyan
- @Description TODO
- @Date 2022/4/28 15:47
@Version 1.0 */ object _14方法的参数 {
// 给定默认值 def add(a:Int = 0,b:Int =0) ={
a + b;}
// 变长参数的演示 使用参数类型 参数个数是0个或者多个 def add2(c:Int) ={
var count = 0; for(i <- c){ count = count + i; } count}
def main(args: Array[String]): Unit = {
println(add()); println(add(10)) println(add(10,15)) // 带着名字的参数,如果没有这个的话,默认设置的只只给了第一个 // 在方法调用的时候,可以通过自定名字赋值 println(add(a=100,b=1000)) println(add2(10,20,30,40,50))} }
<a name="V0jIO"></a>
### 方法的调用:
在scala中,有以下几种方法调用方式,
- 后缀调用法
- 中缀调用法
- 花括号调用法
- 无括号调用法
```scala
/**
* @Author laoyan
* @Description TODO
* @Date 2022/4/28 15:58
* @Version 1.0
*/
object _15方法的调用方式 {
def test() = {
println("hello")
}
def main(args: Array[String]): Unit = {
//后缀调用法 类名.方法名 跟java 一样
Math.abs(-100);
// 中缀调用法 对象名 方法名 参数 for中经常见
1 to 10
// 操作符即方法,在scala中所有的操作符都是方法
1 + 1
// 花括号调用法 适用于方法只有一个参数的情况,可以使用花括号调用法
Math.abs{
println("求绝对值:")
-1998
}
// 无括号调用法
test()
// 如果一个方法没有参数,调用的时候,可以什么都不要了。
test
}
}
10、函数(作用跟方法差不多)
scala是一个函数式编程语言,里面含有大量的函数
定义函数:
val 函数变量名 = (参数名:参数类型, 参数名:参数类型....) => 函数体
对比,方法的定义:
def methodName (参数名:参数类型, 参数名:参数类型) : [return type] = {
// 方法体:一系列的代码
}
函数是一个对象(变量)
类似于方法,函数也有输入参数和返回值
函数定义不需要使用def定义
无需指定返回值类型
/**
* @Author laoyan
* @Description TODO
* @Date 2022/4/28 16:15
* @Version 1.0
*/
object _16函数 {
/**
*
* 函数和方法的区别:
* 方法是隶属于类或者对象的,在运行时,它是加载到JVM的方法区中
可以将函数对象赋值给一个变量,在运行时,它是加载到JVM的堆内存中
函数是一个对象,继承自FunctionN,函数对象有apply,curried,toString,tupled这些方法。方法则没有
函数在scala语言中,地位非常高。
方法是无法赋值给一个变量的,而函数可以。
函数在方法中,可以当做参数去传递。
方法可以转换为函数
*/
def test(a:Int) = {
println("hello")
}
def main(args: Array[String]): Unit = {
val add = (a:Int,b:Int) => a + b
println(add(10,20))
val b = add;
println(b(100,200))
/*val c = test(100);
println(c)*/
// 方法变函数
var c = test _
// 以下这个而是函数的调用
c(100)
}
}
import akka.actor.{Actor, ActorRef, ActorSystem, Props}
import com.typesafe.config.ConfigFactory
import javafx.util.Duration
/**
* @Author laoyan
* @Description TODO
* @Date 2022/5/7 10:32
* @Version 1.0
*/
object DingShi2 {
def main(args: Array[String]): Unit = {
val timeActorSystem: ActorSystem = ActorSystem("timeActorSystem", ConfigFactory.load())
val timeActor: ActorRef = timeActorSystem.actorOf(Props(TimeActor), "timeActor")
//导入一个隐式转换,_ 代表这个类下的所有隐式转换方法 不导入没有办法使用seconds
import scala.concurrent.duration._
// 导入隐式参数 不导入会报错
import timeActorSystem.dispatcher
// 对比上一次的,本次使用的是函数,函数要不上一次的更加灵活
timeActorSystem.scheduler.schedule(
0 seconds,
1 seconds
){
timeActor ! "world"
}
}
}
定时任务中经常使用
import scala.concurrent.duration._ 隐式转换,才能调用 seconds
import timeActorSystem.dispatcher 隐式参数 才能启动定时任务
