一、Scala的介绍

在线学习文档:https://www.runoob.com/scala/scala-tutorial.html

  1. 1Scala是基于Java的语言,必须安装jdk,scala语言也是运行在jvm虚拟机中的。
  2. 2Scala语言是大数据中重要的开发语言重要程度大于Java。是开发Spakr以及Flink的重要语言。
  3. 3Scala语言表达能力强,一行代码抵得上Java多行,开发速度快。
  4. 4Scala名字由来:Scalable Language两个单词相结合;意大利语中“scala”意为“梯子”或“楼梯”
  5. 5Scala之父Martin Odersky(马丁·奥德斯基)
  6. 6Scala的编程思想参照函数式编程(函数式编程非常的重要)
  7. 7、关于版本 2.12.8
  8. - Spark 2.x 使用Scala 2.11预构建,除了版本2.4是用Scala 2.12预构建的。
  9. - Spark 3.0+使用Scala 2.12预构建,删除2.11
  10. - Kafka 2.5.0弃用对Scala 2.11的支持
  11. - 本课程采用2.12.8
  12. 8Scala 是一个符合函数式编程的思想(函数在这个里面是一等公民)
  13. 9scala文件,会被scalac 这个工具编译为.class文件,jvm运行.class文件,不是javac编译的。

image.png

二、环境的安装

1、必须安装jdk ,我们使用的版本是jdk 1.8 版本。
2、下载scala安装包。image.png
3、安装 scala-2.12.8.msi
4、配置环境变量
先找到你的scala的安装目录,配置SCALA_HOME
image.png
image.png
5、scala -version
image.png
6、简单使用一下,进入scala编辑器,输入scala即可进入
image.png
输入:quit 退出编辑。

三、与IDEA的整合

在idea中安装插件,我们选择离线安装:
image.png
选择磁盘上的 scala-intellij-bin-2021.3.20.zip
image.png
image.png
image.png
查看IDEA的版本是多少对应的插件。

四、如何在idea中编写scala代码

1、创建mavan项目

2、在pom.xml中导入scala的开发包

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.scala-lang</groupId>
  4. <artifactId>scala-library</artifactId>
  5. <version>2.12.8</version>
  6. </dependency>
  7. </dependencies>

3、在src\main 下 创建一个文件夹scala
image.png
4、添加scala的支持
image.png
image.png
5、创建一个类,运行一个hello world!image.png
6、创建一个类
image.png
选择Object,不要选class也不要选Case Object
编写代码,右键运行:

  1. object _01基础语法 {
  2. def main(args: Array[String]): Unit = {
  3. println("hello world");
  4. }
  5. }

五、Scala的基础语法

1、变量

  1. /**
  2. * @Author laoyan
  3. * @Description TODO
  4. * @Date 2022/4/28 11:24
  5. * @Version 1.0
  6. */
  7. object _02变量 {
  8. def main(args: Array[String]): Unit = {
  9. /**
  10. * java 中声明
  11. * int a = 0;
  12. * 在scala中 使用 val 或者 var 来定义变量
  13. * 格式如下:
  14. * var/val 变量名:变量的类型 = 初始值
  15. * var : 可以修改值
  16. * val : 它修饰的变量,不能再次赋值 ,类似于Java 的final
  17. */
  18. var a:Int = 0;
  19. val b:Int = 10;
  20. a = 100;
  21. // b = 200;
  22. /**
  23. * 在scala 中,可以省略 ;
  24. * 可以省略 数据类型,scala 会根据我们的值推导出我们的 变量的类型
  25. */
  26. var c = 100
  27. val name:String = "张三"
  28. val name2 = "张三"
  29. println(name)
  30. println(c)
  31. // 优先使用 val ,如果定义的变量确实需要修改 它的值,这个时候再考虑使用var
  32. // lazy 惰性赋值
  33. /*
  34. 语法: lazy val/var 变量名= 变量值
  35. 使用lazy修饰的变量,一般是不加载到jvm中的,只有后面使用到了这个变量才会去加载这个值。
  36. 这样的好处是:不浪费jvm资源。一般适用于该变量对应的值非常的大,比如是一个大数组,大集合,大语句等
  37. */
  38. lazy val sql = "此处是一个非常长的SQL语句"
  39. println(sql)
  40. }
  41. }

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、数据类型

image.png
我们观察到scala中的数据类型都是首字母大写的,它没有Integer ,它有Int
image.png

# 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是所有类的子类,那么它可以赋值为任何类型

image.png

4、运算符

image.png
补充:

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  隐式参数  才能启动定时任务