• 第一章 Scala基础篇


    一、Scala基础语法

    ===

    (一) 变量、类型、操作符

    1.变量申明

    ●Java中:

    //数据类型 变量名 = 值;
    final int b = 2;
    b = 23; //错误!!! final修饰的变量不可变
    int a = 1;
    a = 22;
    

    ●在Scala中:

    //val/var 变量名:变量类型 = 变量值
    val a:Int = 1
    a =2 //错误!!!! val修饰的变量不可以被重新赋值,类似于Java中的final
    var b:Int = 1
    b = 2
    

    ●说明

    var声明的变量可以重新赋值

    val声明的变量不可以重新赋值,或称之为不可变变量/只读变量。相当于java里用final修饰的变量

    ●注意:

    Scala中变量声明类型可以省略,解析器会根据值进行推断

    Scala中语句最后不需要添加分号

    val和var声明变量时都必须初始化

    为了减少可变性引起的bug,应该尽可能地使用不可变变量val。(推荐使用val)

    如果想在变量名、类名等定义中使用语法关键字(保留字),可以配合反引号:

    val `val` = 123    //(符号为键盘上Esc下面的键)
    

    ●Type关键字

    Scala 里可以通过type 关键字来声明类型。

    type 相当于声明一个类型别名:

    // 把String 类型用S 代替
    type S = String
    val name: S = "bigdata"
    println (name)
    

    ●懒值

    应用场景

    ​ 当val被声明为lazy时,初始化将被推迟,只有当这个变量真正被使用到的时候,变量的赋值代码才会真正的执行

    ​ lazy适用于初始化开销较大的场景

    ●代码演示

    package com.flyingAfish.baseTest
    
    object VariableDemo {
      def main(args: Array[String]): Unit = {
        val name:String = "fizz"
        //name = "jack ma" //错误,val修饰的变量不能被重新赋值
        var money:Int = 8888
        money = 565//var修饰的变量可以重新赋值
    
        val age = 18 //:Int 类型可以省略,编译器会自动推断age的类型
        //age = "fizz" //错误,因为scala是强类型
    
        type str = String //type关键字可以给类型起别名
        val animal:str = "fish"
      
        //当val被声明为lazy时,初始化将被推迟,只有当这个变量真正被使用到的时候,变量的赋值代码才会真正的执行
        //lazy适用于初始化开销较大的场景
        val msg1 = init()
        println("我是按顺序执行的")
        println(msg1)
        println("===============")
        lazy val msg2 = init()
        println("我先于init方法执行")
        println(msg2)
      }
    
      //定义一个方法,输出一句话并返回一个字符串
      def init() ={
        println("init方法执行了")
        "msg"
      }
    }
    
    /*	init方法执行了
        我是按顺序执行的
        msg
        ===============
        我先于init方法执行
        init方法执行了
        msg
    */
    

    2.字符串

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

    ●双引号

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

    ●三引号

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

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

    ●使用插值表达式

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

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

    ●代码演示

    package com.flyingAfish.baseTest
    
    object StringDemo {
      def main(args: Array[String]): Unit = {
        val name = "fizz"
        val sql =
          """
            |select *			// | 竖条为编译器自动添加
            |from table
            |where name = fizz
          """.stripMargin		//.stripMargin 编译器自动添加
        val sql2 =
          s"""					//s 为编译器自动添加
            |select *
            |from table
            |where name = ${name}
          """.stripMargin		
    
        println(name)
        println(sql)
        println(sql2)
      }
    }
    /*
    	fizz
    
        select *
        from table
        where name = fizz
    
        select *
        from table
        where name = fizz  
    */
    

    3.数据类型

    ●数值类型

    Scala和Java一样,有多种数值类型Byte、Char、Short、Int、Long、Float、Double类型和1个Boolean类型。

    Boolean true 或者 false
    Byte 8位, 有符号
    Short 16位, 有符号
    Int 32位, 有符号
    Long 64位, 有符号
    Char 16位, 无符号
    Float 32位, 单精度浮点数
    Double 64位, 双精度浮点数
    String 其实就是由Char数组组成

    ●继承体系

    ![img](file:///C:UsersADMINI~1AppDataLocalTempksohtml19704wps2.png)

    ●Any

    在scala中,所有的类,包括值类型,都最终继承自一个统一的根类型Any,Any类是根节点

    Any中定义了isInstanceOf、asInstanceOf方法,以及哈希方法等。AnyVal和AnyRef都扩展自Any类。

    ​ isInstanceOf:是否继承自某类

    ​ asInstanceOf:强制类型转换

    ●AnyVal-所有值类型的基类,所有的值都是类类型都是AnyVal的子类

    - scala.Double

    - scala.Float

    - scala.Long

    - scala.Int

    - scala.Char

    - scala.Short

    - scala.Byte

    上面是数字类型。

    还包括scala.Unit 和 scala.Boolean 是非数字类型。

    ●AnyRef-是所有引用类型的基类。

    ​ 除了值类型,所有其他类型都继承自AnyRef

    ●Null

    ​ 是所有引用类型的子类型,Null类只有一个实例对象,null,类似于Java中的null引用。null可以赋值给任意引用类型,但是不能赋值给值类型

    ●Nothing

    是所有类型的子类型。Nothing类型没有实例。它对于泛型结构是有用处的,举例:

    空列表Nil的类型是List[Nothing],它是List[T]的子类型,T可以是任何类。

    Nothing可以作为没有正常返回值的方法的返回类型,非常直观的告诉你这个方法不会正常返回,而且由于Nothing是其他任意类型的子类,他还能跟要求返回值的方法兼容。

    ●Unit

    用来标识过程,也就是没有明确返回值的函数。

    由此可见,Unit类似于Java里的void。Unit只有一个对象实例(),这个实例也没有实质的意义。

    ●注意

    1.Scala并不刻意区分基本类型 和 引用类型,所以这些类型都是对象,可以调用相对应的方法。

    2.每一种数值类型都有对应的Rich类型,如RichInt、RichChar等,为基本类型提供了更多的有用操作。(重要

    3.String直接使用的是java.lang.String类,另外在scala.collection.immutable.StringOps中还定义了更多的操作。在需要时String能隐式转换为StringOps,因此不需要任何额外的操作,String就可以使用这些方法。

    4.操作符

    Scala中的+ - * / %等操作符的作用与Java一样,位操作符 & | ^ >> <<也一样。

    ●注意:

    1.Scala中的操作符实际上是方法

    2.Scala中没有++、--操作符,需要通过+=、-=来实现同样的效果(因为++ -- 前置后置容易混淆)

    3.+ - * / %是方法,那么就可以进行操作符重载,完成特殊的运算(也就是自己在类中定义+ - * / %方法表示特殊的运算)

    ●高级:

    1)中置操作符,

    //A操作符B 等同于 A.操作符(B) 
    val a = 1
    val b = 2
    var c = a + b     
    var d = a.+(b)	//等同与上式
    

    2)后置操作符,

    ​ A操作符 等同于 A.操作符,如果操作符定义的时候不带()则调用时不能加括号

    math.random
    

    3)前置操作符,

    ​ +、-、!、~等操作符 A等同于 A.unary_操作符。

    var b = true
    b = !b
    b = b.unary_!	//等同与上式
    

    4)赋值操作符,

    ​ A操作符=B 等同于 A=A操作符B

    a += 1
    a = a + 1	//等同与上式
    

    ●代码演示

    package com.flyingAfish.baseTest
    
    object OperatorDemo {
      def main(args: Array[String]): Unit = {
        var a = 1
        var b = 2
        val result = a + b
        println(result)//3
        val result2 = a.+(b) //在Scala中运算符其实是方法
        println(result2)//3
        //a++ //错误,在Scala中为了避免混淆,不支持++ --
        a += 1 //a = a + 1
        println(a)//2
      }
    

    (二)循环判断

    1.块表达式

    定义变量时可以使用 {} 包含一系列表达式,其中{}块的最后一个表达式的值就是整个块表达式的值。

    ●代码演示

    package com.flyingAfish.baseTest
    
    object E_BlockDemo {
      def main(args: Array[String]): Unit = {
        var a = 1
        var b  =2
        var c = {
          a = a + b
          b = a + b
          var i = a + b
          i 		//注意:{}块表达式的最后一行是整个表达式的值
        }
        println(c)//8
      }
    }
    

    2.条件表达式

    Scala条件表达式的语法和Java一样,只是更加简洁,且Scala中if else表达式是有返回值的

    ●注意:

    Scala中没有三元表达式

    如果if或者else返回的类型不一样,就返回Any类型

    对于没有返回值的,使用Unit,写做(),相当于java中的void

    ●代码演示

    package com.flyingAfish.baseTest
    
    object ConditionDemo {
      def main(args: Array[String]): Unit = {
        val sex1 = "male"
        val sex2 = "female"
    
        //if表达式有返回值
        val result1:String = if(sex1 == "male"){
          "男"
        }else{
          "女"
        }
        println(result1)
    
        val result2:String = if(sex1 == "male") "男" else "女"
        println(result2)
    
        //如果返回值类型不一致,返回Any
        val result3:Any = if(sex2 == "male"){
          "男"
        }else{
          0
        }
        println(result3)
    
        //()表示没有返回值,即Unit,相当于Java中的void
        val result4:Unit = if(sex2 == "male"){
          println("男")
        }else{
          println("女")
        }
        println(result4)//()
      }
    }
    

    3.循环表达式

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

    ●简单for循环:

    ​ for (变量 <- 表达式/数组/集合) {循环体}

    for(i <- 1 to 10){println(i)} //循环打印1~10
    

    ●嵌套for循环

    ​ for (变量1 <- 表达式/数组/集合; 变量2 <- 表达式/数组/集合) {循环体}

    for(i <- 1 to 9; j <- 1 to 9){
         if(i >= j ) print(s"${j} * ${i} = ${j*i}")
         if(j == 9) println()
    }
    

    ●守卫

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

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

    for(i <- 1 to 10 if i % 3 == 0) println(i) //3,6,9
    

    ●for推导式(有返回值)

    ​ 在for循环体中,可以使用yield表达式构建出一个集合,我们把使用yield的for表达式称之为推导式

    ​ 即可以使用for推导式生成一个新的集合(一组数据)

    //该for表达式会构建出一个集合
    val res = for(i <- 1 to 10) yield i * 10 //10,20,30,40...
    

    ●注意:

    ​ while、for语句本身没有值,即整个while语句的结果是Unit类型的()

    var n = 1;
    val result:unit = while(n <= 10){
      	n += 1
    }
    println(result)
    println(n)
    

    ●代码演示

    package com.flyingAfish.baseTest
    
    object LoopDemo {
      def main(args: Array[String]): Unit = {
        //1 to 10 ===> [1,10]
        val res1 = 1 to 10 //Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
        //1 until 10 ===> [1,10)
        val res2 = 1 until 10 //Range(1, 2, 3, 4, 5, 6, 7, 8, 9)
        //1 to 10 ===> [1,10],步长为2
        val res3 = 1 to 10 by 2 //Range(1, 3, 5, 7, 9)
        println(res1)
        println(res2)
        println(res3)
    
        //1.简单for循环
        for(i <- 1 to 10) println(i)
    
        println("===========分割线==========")
        //2.嵌套for循环--传统写法
        for(i <- 1 to 9){
          for(j <- 1 to 9){
            if(i >= j){
              print(s"${j} * ${i} = ${j * i} 	")
            }
          }
          println()
        }
        println("===========分割线==========")
        //2.嵌套for循环--Scala骚气写法
        for(i <- 1 to 9;j <- 1 to 9){
          if(i >= j) print(s"${j} * ${i} = ${j * i} 	")
          if(j == 9) println()
        }
        println("===========分割线==========")
        //3.守卫
        //需求打印1~10中3的倍数
        for(i <- 1 to 10){
          if(i % 3 == 0) println(i)
        }
        println("===========分割线==========")
        for(i <- 1 to 10 if(i % 3 == 0)) println(i)
    
        println("===========分割线==========")
        //4.for推导式
        //需求把1~10中的每一个数扩大10倍形成一个新的集合
        //使用yield关键字可以生成一个新的集合
        val col = for(i <- 1 to 10) yield i * 10
        println(col)//Vector(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
    
        println("===========分割线==========")
        //5.注意:while循环没有返回值
        var n =1
        val result = while (n <= 100){
          n += 1
          n
       }
        println(n)//101
        println(result)//()
      }
    }
    

    (三)方法和函数

    1.方法

    def 方法名(参数名1: 参数类型1, 参数名2: 参数类型2) : 返回类型 = {方法体}

    img

    ●语法细节

    1. 方法的返回值类型和return可以不写,编译器可以自动推断出来

    2. 对于递归方法必须指定返回类型

    3. 如果方法没有返回值,返回Unit类型(类似于void,也可以不写)

    4. 返回值类型有多种情况则返回Any

    5. 带有默认值参数的方法,调用时,可以给定新值,也可以使用默认值

    6. 可以通过参数名来指定传递给哪一个参数,这样传递参数时就可以不按照顺序传递

    7. 方法没有参数,调用时可以省略(),如果定义时()省略,调用时则必须省略

    8. 可变参数使用 变量名: 类型* (类似Java的...

    ●代码演示

    package com.flyingAfish.baseTest
    
    object MethodDemo {
      def main(args: Array[String]): Unit = {
        val result: Int = factorial(3)
        println(result)//6
        println(noReturnValue())//()
        //val resutl2: Int = haveDefaultParam(b=2)//102
        //val resutl3: Int = haveDefaultParam(a=1,b=2)//3
        //val resutl4: Int = haveDefaultParam(1,2)//3
        val resutl5: Int = haveDefaultParam(b=2,a=1)//3
        //println(resutl2)
        //println(resutl3)
        //println(resutl4)
        println(resutl5)
    
        noParam
    
        val sum: Int = multiParam(1,2,3,4,5)//15
        println(sum)
      }
      
      
      //def 方法名(参数名1:参数类型,参数名1:参数类型):返回值类型 = {方法体}
      //1.方法的返回值类型和return可以不写,编译器可以自动推断出来
      def omitReturnValue() ={
         1
      }
    
      //2.对于递归方法,必须指定返回类型
      //需求:求n的阶乘 ==> 10的阶乘=1*2*3...*10 == 10 * 9 * 8 .....
      def factorial(n:Int):Int = {
        if (n == 1){
          1
        }else{
          n * factorial(n-1)
        }
      }
    
      //3.如果方法没有返回值,返回Unit类型(类似于void,也可以不写)
      def noReturnValue():Unit={
        println("m3")
      }
      //4.返回值类型有多种情况则返回Any或者不写
      val sex = "male"
      def multiReturnValue():Any={
        if (sex == "male"){
          "男"
        }else{
          0
        }
      }
      //5.带有默认值参数的方法,调用时,可以给定新值,也可以使用默认值
      //6.可以通过参数名来指定传递给哪一个参数,这样传递参数时就可以不按照顺序传递
      def haveDefaultParam(a:Int=100,b:Int):Int={
        println("a="+a)
        println("b="+b)
        a + b
      }
      //7.方法没有参数,调用时可以省略(),如果定义时()省略,调用时则必须省略
      def noParam={
        println("m7")
      }
      //8.可变参使用 变量名:类型* (类似Java的...)
      //定义了一个方法可以传递多个int值,并返回他们的和
      def multiParam(args:Int*):Int={
        var sum = 0
        for (i <- args){
          sum +=i
        }
        sum
      }
    }
    

    2.函数

    ●完整语法:

    ​ val函数名称 :(参数类型)=>函数返回值类型 = (参数名称:参数类型)=>函数体

    val sum:(Int,Int)=>Int = (a:Int,b:Int)=>{a + b}
    

    ●简写语法:

    ​ val函数名称 = (参数名称:参数类型) => 函数体

    val max = (a:Int,b:Int)=>{
        if(a > b) a
        else b
    }
    

    ●符号解释

    ​ = 表示将右边的函数 赋给 左边的变量

    ​ => 左面表示输入参数名称和类型,右边表示函数的实现和返回值类型

    3.方法和函数的区别

    ●方法:

    ​ 和之前学习Java时理解的方法一样,是封装了完成某些功能的代码块,所属于某一个类或对象

    ●函数:

    ​ 在Scala中,函数是头等公民,函数是一个对象,那么既然是对象的话,函数就可以赋值给变量 或者 当作参数被传递,还可以 使用函数打点调用方法

    ​ Scala中函数继承自FuctionN,带有一个参数的函数的类型是function1,带有两个是function2,以此类推

    ●证明函数是对象

    ●函数是对象,可以打点调方法

    package com.flyingAfish.baseTest
    
    object FunctionDemo {
      def main(args: Array[String]): Unit = {
        //val函数名称 = (参数名称:参数类型) => 函数体
        val add1 = (a:Int) => {a }
        val add2 = (a:Int,b:Int) => {a + b}
        val add3: (Int, Int, Int) => Int = (a:Int, b:Int, c:Int) => {a + b + c}
        println(add1)//<function1>
        println(add2)//<function2>
        println(add3)//<function3>
        
        //结论:函数是对象,有N个参数打印的时候就是functionN
        val str: String = add1.toString()//函数是对象,所以可以调用方法
        println(str)//<function1>
        
        //函数一般用法
        println(add2(3,2))//5
      }
    }
    

    ●函数可以赋值给变量并将可以当作参数进行传递

    ​ 定义一个函数,接收两个参数,返回两个数的和

    ​ 定义一个方法,接收两个参数和一个函数,并在方法体中调用函数,将两个参数传递给函数

    package com.flyingAfish.baseTest
    
    object FunctionDemo {
      def main(args: Array[String]): Unit = {
        //函数可以赋值给变量并将可以当作参数进行传递
        //定义一个函数,接收两个参数,返回两个数的和
        val add = (a:Int,b:Int) => a + b //证明了函数是对象,且函数可以赋值给变量
        val result1: Int = operator(1,2,add) //证明了函数是对象,且函数可以当作参数进行传递
        println(result1)//3
    
        //函数的好处:
        //可以将我们要进行的操作进行传递!!!
        //也就是函数式编程的核心思想:行为参数化!!!
        val result2: Int = operator(1,2, (a,b)=> a*b)
        println(result2)
    
        println("=======================")
        //再来体会一下:行为参数化!!!
        //val list = List(1,2,3,4,5)
        val list = 1 to 5
        //val f = (i:Int) => println(i)
        //list.foreach((i:Int) => println(i))
        //list.foreach(i => println(i))
        //list.foreach(println(_))
        list.foreach(println)
      }
    
      //定义一个方法,接收两个参数和一个函数,并在方法体中调用函数,将两个参数传递给函数
      def operator(a:Int,b:Int,fun:(Int,Int)=>Int) ={
        fun(a,b)
      }
    }
    

    ●方法可以转换成函数

    ​ 证明方法无返回值也可以调用

    ​ Java里面方法无返回值不能调用

    package com.flyingAfish.baseTest
    
    object I_FunctionDemo4 {
        def main(args: Array[String]): Unit = {
            println(fizz()) //() 证明函数五返回值也可以条用,打印的是空括号()
            println(fizz _) //下划线 _可以将方法变成函数 //<function0>
        }
        
        def fizz() = {
            
        }
    }
    

    4.总结

    ●定义方法:

    ​ def 方法名(参数名1: 参数类型1, 参数名2: 参数类型2) : 返回类型 = {方法体}

    ●定义方法简写法:

    ​ def 方法名(参数名1: 参数类型1, 参数名2: 参数类型2) = {方法体}

    ​ def 方法名 = {方法体}

    ●定义函数完整语法:

    ​ val函数名称 :(参数类型)=>函数返回值类型 = (参数名称:参数类型)=>函数体

    ●定义函数简写语法:

    ​ val函数名名称 = (参数名称:参数类型) => 函数体

    ![img](file:///C:UsersADMINI~1AppDataLocalTempksohtml19704wps4.png)

    ●注意:

    ​ 严格的来说,函数与方法是不同的东西。定义方式上也有很多的区别

    ​ 但是在Scala中,函数本身是对象,方法可以通过下划线_转换为函数。

    结论:在Scala中

    ​ 方法可以转换为函数,函数本质上就是对象

    ​ 函数式编程的核心思想、灵魂所在:行为参数化!

    二、Scala常用数据结构/集合

    (一)Scala集合分类和继承体系

    1.分类

    ●集合分类-按照数据结构特点分

    ​ Scala的集合都扩展自Iterable特质(先理解为接口)

    ​ 有三大类:Seq序列(List)、Set、Map映射

    ●集合分类-按照可变和不可变分(注意:这里的可变和不可变指的是集合的内容和长度,和之前的var/val有区别)

    ​ 大部分的集合Scala都同时提供了可变和不可变的版本。

    ​ 开发时建议Scala优先采用不可变集合(默认即为不可变),满足不了需求是再使用可变集合

    ●可变集合和不可变集合相应的包为:

    ​ 不可变集合:scala.collection.immutable (默认)

    ​ 可变集合: scala.collection.mutable

    ●注意

    val和可变不可变

    ​ var和val指的是:变量能否被重新赋值

    ​ 集合可不可变指的是:集合长度或内容可不可变

    对于数组:

    ​ 不可变数组Array:长度不可变,元素可变(定长数组)

    ​ 可变数组ArrayBuffer:长度和里面的元素都可变(变长数组)(注意:Java里面数组长度不可变)

    对于其他集合:

    ​ 不可变集合immutable:长度和内容都不可变,如果调用添加或者删除方法,会产生新的集合,原集合不变

    ​ 可变集合mutable:长度和内容都可变

    总结:

    ​ 开中优先使用不可变,如果满足不了需求再使用可变

    2.继承体系

    ●不可变集合(immutable )继承层次:

    ![img](file:///C:UsersADMINI~1AppDataLocalTempksohtml19704wps5.png)

    ●可变集合(mutable)继承层次:

    ![img](file:///C:UsersADMINI~1AppDataLocalTempksohtml19704wps6.png)

    (二)数组

    ●不可变/定长数组:

    val/var 变量名= new Array[T](数组长度)//scala.collection.immutable包下,不需要导包,默认就是
    val/var 变量名 = Array(元素1, 元素2, 元素3...)
    

    ●可变/变长数组:

    val/var 变量名 = ArrayBuffer[T]() //需要手动导入import scala.collection.mutable.ArrayBuffer包
    val/var 变量名 = ArrayBuffer(元素1, 元素2, 元素3...)
    

    ●数组操作

    指定分隔符 mkString

    将数组转换成数组缓冲 toBuffer(打印Buffer可以看到数组内容)

    根据索引获取元素 ()

    添加元素 +=

    删除元素 -=

    追加一个数组到变长数组 ++=

    往指定角标插入元素 insert

    删除指定角标的元素 remove

    定长=>>变长 toBuffer

    变长=>>定长 toArray

    多维数组 Array.ofDimDouble

    ●遍历数组

    1.可以for循环直接遍历数组

    2.可以遍历下标再根据下标获取元素

    3.回忆一下生成指定范围的序列

    0 to n 生成[0,n]

    0 until n 生成[0,n)

    ●数组其他常用方法

    在Scala中,数组上的某些方法对数组进行相应的操作非常方便!

    sum求和

    max求最大值

    min求最小值

    sorted排序

    reverse反转

    ●代码演示

    package com.flyingAfish.baseTest
    import scala.collection.mutable
    
    object ArrayDemo {
      def main(args: Array[String]): Unit = {
        val arr: Array[Int] = Array(5,6,7,1,2,3,4,8,9)//不可变
        //不可变==>可变
        val arr2: mutable.Buffer[Int] = arr.toBuffer
        //可变==>不可变
        val arr3: Array[Int] = arr2.toArray
    
        //遍历
        for(i <- arr) println(i)
        println("====================")
        //arr.foreach((i:Int)=>println(i))
        //arr.foreach(i=>println(i))
        //arr.foreach(println(_))
        arr.foreach(println)//行为参数化
        println("====================")
        //逆序
        for(i <- arr.reverse) println(i)
        println("====================")
        //通过索引遍历
        for(i <- 0 until arr.length) println(arr(i))
    
        //统计
        println(arr.sum)
        println(arr.max)
        println(arr.min)
        println(arr.reverse.mkString(","))
        println(arr.sorted.mkString(","))//按照默认的排序规则排序-升序
        println(arr.sortBy((i:Int) => -i).mkString(",")) //降序
        println(arr.sortWith((x:Int,y:Int) => x > y).mkString(","))//降序
    
      }
    }
    

    (三)元组

    ​ 元组也是可以理解为一个容器,可以用来存放各种相同或不同类型的数据。例如:姓名,年龄,性别,出生年月。

    元组的元素是不可变的

    ●创建元组

    ​ 使用括号来定义元组

    val/var 元组 = (元素1, 元素2, 元素3....)
    val animal = ("fish","cat","dog")
    val world = ("fizz",34,animal,34.43)
    

    ​ 使用箭头来定义元组(元组只有两个元素)

    val/var 元组 = 元素1->元素2 //对偶/二元组是最简单的元组(k,v)
    val animal: (String, String) = ("fizz", "dgo")
    val dog: (String, Int) = "god" -> 3
    

    ●获取元组中的值

    //使用下划线加脚标 ,例如 元组名._1  元组名._2 元组名._3
    val animal: (String, String) = ("fizz", "dgo")
    val dog: (String, Int) = "dog" -> 3
    val name: String = animal._1
    val age: Int = dog._2
    

    注意:元组中的元素脚标是从1开始的

    ●将对偶(二元组)组成的数组转换成映射(映射就相当于Java中的Map,后面会讲)

    将对偶/二元组的集合转换成映射:

    调用其toMap 方法

    ![img](file:///C:UsersADMINI~1AppDataLocalTempksohtml19704wps7.png)

    ●遍历

    ​ 可以调用元组的productIterator方法获取迭代器对象进行遍历

    ●代码演示

    package com.flyingAfish.baseTest
    
    object TupleDemo {
      def main(args: Array[String]): Unit = {
        //使用括号来定义元组
        //val/var 元组 = (元素1, 元素2, 元素3....)
        val t1: (String, Double, Int) = ("hadoop",3.14,110) //元组里可以存放不同类型的元素
        //使用箭头来定义元组(元组只有两个元素)
        //val/var 元组 = 元素1->元素2 //对偶/二元组是最简单的元组(k,v)
        val t2: (String, Int) = "age"->18
        val t3 = ("age",18)
        println(t1)
        println(t2)
        println(t3)
        println(t1.getClass)
        println(t2.getClass)
        println(t3.getClass)
    
        //获取元素
        println(t1._1)
        println(t1._2)
        println(t1._3)
    
        println("============")
        //val iterator: Iterator[Any] = t1.productIterator
        for(i <- t1.productIterator) println(i)
    
        //将二元组组成的集合转成map
        val ts = Array(("jack",60),("tom",70),("rose",80))
        val map: Map[String, Int] = ts.toMap
        println(map)//Map(jack -> 60, tom -> 70, rose -> 80)
      }
    }
    

    (四)List

    ●高能预警

    ​ List操作的API方法和符号特别特别多,不用刻意去记,后续学习中会使用一些常见的,用的多了就掌握了!

    ●List介绍

    ​ 列表是scala中最重要的、也是最常用的数据结构。在scala中,也有两种列表,一种是不可变列表、另一种是可变列表

    但都具备以下性质:

    ​ 可以保存重复的值

    ​ 有先后顺序

    ●不可变列表(默认)

    ​ import scala.collection.immutable._

    ​ 创建方式1.使用List(元素1, 元素2, 元素3, ...)来创建一个不可变列表

    val/var 变量名 = List(元素1, 元素2, 元素3...)
    val strings: List[String] = List("book","subject","car")
    val book: List[Any] = List("English", 32, "chinese", 300)
    

    ​ 创建方式2.使用::方法创建一个不可变列表

    val/var 变量名 = 元素1 :: 元素2 :: Nil 
    val money: List[Int] = 34 :: 34 :: 344 :: Nil
    

    注意:

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

    ●可变列表

    ​ import scala.collection.mutable._

    ​ 创建方式1.使用ListBuffer元素类型创建空的可变列表

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

    ​ 创建方式2.使用ListBuffer(元素1, 元素2, 元素3...)创建可变列表

    val/var 变量名 = ListBuffer(元素1,元素2,元素3...)
    val personName: ListBuffer[Any] = ListBuffer("kashke",34,"wangzida")
    

    ●head和tail

    ​ 在Scala中列表要么为Nil(Nil表示空列表)

    ​ 要么是一个head元素加上一个tail列表。

    //head为列表第一个元素,tail为列表除第一个元素外的元素列表
    val list1 = List(1,2,3,4,5)
    println(list1.head)//1
    println(list1.tail)//List(2, 3, 4, 5)
    val list = List(1)
    println(list)//List(1)
    println(list.head)//1
    println(list.tail)//List()
    

    ●::操作符

    :: 操作符是将给定的头和尾创建一个新的列表,原列表不变  
    :: 操作符是右结合的,如1 :: 5 :: 2 :: Nil相当于 1 :: (5 :: (2 :: Nil))   ==> List(1,5,2)
    

    ●可变列表操作

     获取/更改元素(使用括号访问(索引值))
     添加元素(+=)
     追加一个列表(++=)
     删除元素(-=)
     转换为List(toList)
     转换为Array(toArray)
    

    ●扩展:list其他操作符(了解)

    ::  (x: A): List[A]                            在列表的头部添加一个元素或列表
    +:  (elem: A): List[A]                         在列表的头部添加一个元素
    :+  (elem: A): List[A]                         在列表的尾部添加一个元素
    ++  [B](that: GenTraversableOnce[B]): List[B]  从列表的尾部添加另外一个列表
    :::  (prefix: List[A]): List[A]                   在列表的头部添加另外一个列表
    

    ●扩展:等价操作(了解)

    val left = List(1,2,3)
    val right = List(4,5,6)
    //以下操作等价
    left ++ right      // List(1,2,3,4,5,6)
    right.:::(left)     // List(1,2,3,4,5,6)
    //以下操作等价
    0 +: left    //List(0,1,2,3)
    left.+:(0)   //List(0,1,2,3)
    //以下操作等价
    left :+ 4    //List(1,2,3,4)
    left.:+(4)   //List(1,2,3,4)
    //以下操作等价
    0 :: left      //List(0,1,2,3)
    left.::(0)     //List(0,1,2,3)
    

    ●代码演示

    package com.flyingAfish.baseTest
    
    object ListDemo {
      def main(args: Array[String]): Unit = {
        //●不可变列表
        //val/var 变量名 = List(元素1, 元素2, 元素3...)
        val list1 = List(1,2,3,4,5)
        //val/var 变量名 = 元素1 :: 元素2 :: Nil
        val list2 = 1::2::Nil //List(1,2)
    
        //●可变列表
        //val/var 变量名 = ListBuffer[Int]()
        import scala.collection.mutable.ListBuffer
        val list3 = ListBuffer[Int]()
        //val/var 变量名 = ListBuffer(元素1,元素2,元素3...)
        val list4 = ListBuffer(1,2,3,4)
        list3.append(1,2,3)
    
        println(list1)
        println(list2)
        println(list3)//ListBuffer(1, 2, 3)
        println(list4)
        //List(1, 2, 3, 4, 5)
        //List(1, 2)
        //ListBuffer(1, 2, 3)
        //ListBuffer(1, 2, 3, 4)
    
        println(list1.head)//1
        println(list1.tail)//List(2, 3, 4, 5)
        val list = List(1)
        println(list)//List(1)
        println(list.head)//1
        println(list.tail)//List()
    
        println("============")
        list3.remove(1)//根据索引删除
        println(list3)//ListBuffer(1, 3)
        list3 += 4
        list3 -= 1
    
        val list5 = list3.toList
        val list6 = list3.toArray
    
        val list7 = 0 +: list3
        println(list7)//ListBuffer(0, 3, 4)
        
        list7
    
        //遍历
        for(i <- list3) println(i)
        list3.foreach(println)
      }
    }
    

    (五)队列

    ●说明

    ​ 队列数据存取符合先进先出的策略

    ​ 有 scala.collection.mutable.Queue 和 scala.collection.immutable.Queue

    ​ 一般来说我们在开发中队列通常使用可变队列(特殊),其他都推荐使用不可变

    ●常见操作

    ​ enqueue入队/+=追加

    ​ dequeue出队

    ●代码演示

    package com.flyingAfish.baseTest
    import scala.collection.mutable
    
    object DueueDemo {
      def main(args: Array[String]): Unit = {
        //队列在开发中一般使用可变队列
        val q = mutable.Queue[Int]()
        q.enqueue(1)
        q.enqueue(2)
        q.enqueue(3)
        q += 4
        q.+=(5)
        println(q)//Queue(1, 2, 3, 4 , 5)
        val i: Int = q.dequeue()
        println(i)//1
      }
    }
    

    (六)Set

    ●Set说明

    Set代表一个没有重复元素的无序集合;即无法加入重复元素且不保证插入顺序的。

    ●不可变Set(默认)

    import scala.collection.immutable._

    ​ 1.创建一个空的不可变集,语法格式:

    val/var 变量名 = Set[类型]()
    val movie = Set[String]()
    

    ​ 2.给定元素来创建一个不可变集,语法格式:

    val/var 变量名 = Set(元素1, 元素2, 元素3...)
    val fresh = Set("apple","pear","apricot")
    

    ●可变Set

    import scala.collection.mutable._

    ​ 格式相同,导包不同

    Set操作

    方法 描述
    def +(elem: A): Set[A] 为集合添加新元素,并创建一个新的集合,除非元素已存在
    def -(elem: A): Set[A] 移除集合中的元素,并创建一个新的集合
    def contains(elem: A): Boolean 如果元素在集合中存在,返回 true,否则返回 false。
    def &(that: Set[A]): Set[A] 返回两个集合的交集
    def &~(that: Set[A]): Set[A] 返回两个集合的差集
    def ++(elems: A): Set[A] 合并两个集合

    ●代码演示

    package com.flyingAfish.baseTest
    
    object SetDemo {
      def main(args: Array[String]): Unit = {
        //●不可变Set(默认)
        //val/var 变量名 = Set(元素1, 元素2, 元素3...)
        val set1 = Set(1,2,3,4,5,6,7)
    
        //●可变Set
        //格式相同,导包不同
        //val/var 变量名 = Set[类型]()
        import scala.collection.mutable._
        val set2 = Set[Int]()
        set2.add(1)
        set2.add(2)
        set2.add(3)
        val set3 = set2 + 4
        val set4 = set2 - 1
        set2.remove(2)
        println(set2)//Set(1, 3)
        println(set3)//Set(1, 2, 3, 4)
        println(set4)//Set(2, 3)
    
        val set5 = set2 ++ set3 //并集
        println(set5)//Set(1, 2, 3, 4)
    
        val set6 = set3 & set2
        println(set6)//Set(1, 3)//交集
    
        val set7 = set3 &~ set2//差集
        println(set7)//Set(2, 4)
    
    //遍历和其他集合一样
      }
    }
    

    (七)Map

    ●说明

    ​ 在Scala中,把哈希表这种数据结构叫做映射类比Java的map集合

    ●不可变Map

    import scala.collection.immutable.Map

    ​ 格式一:使用箭头

    val/var map = Map(键->值, 键->值, 键->值...)   // 推荐,可读性更好
    val hero = Map("fish"->"潮汐海灵","zeus"->"宙斯","baiqi"->"白起")
    

    ​ 格式二:利用元组

    val/var map = Map((键, 值), (键, 值), (键, 值), (键, 值)...)
    val subject = Map(("math","数学"),("English","英语"),("physics","物理"))
    

    ●可变Map

    import scala.collection.mutable.Map

    ​ 格式相同,导包不同

    ●获取值

    map(键)
    map.get(键)
    map.getOrElse(键,默认值)//根据键取值,如果取到了则返回,没取到返回指定的默认值
    

    ●修改值

    map(键)=值
    

    ●增加值

    map.put(键,值)
    

    ●代码演示

    package cn.fizz.collection
    
    object MapDemo {
      def main(args: Array[String]): Unit = {
        //●不可变Map
        //●可变Map
        //格式相同,导包不同
        import scala.collection.mutable._
        //格式一:使用箭头val/var map = Map(键->值, 键->值, 键->值...)   // 推荐,可读性更好
        val map1 = Map("tom"->60,"rose"->70,"jack"->80,"zhaosi"->100)
        //格式二:利用元组val/var map = Map((键, 值), (键, 值), (键, 值), (键, 值)...)
        val map2 = Map(("tom",60),("rose",70),("jack",80),("zhaosi",100))
        map1.put("lily",90)
        map1.remove("tom")
        println(map1)
        println(map2)
    
        //根据key取值
        //Option是None和Some的父类
        //None表示空的,什么都没有
        //Some表示里面有一个元素,在使用get就可以取出来
        val op: Option[Int] = map1.get("zhaosi")
        println(op.get)//100
    
        //直接使用get方法不好,如果没有指定的key,继续操作可能会报错
        //val op2: Option[Int] = map1.get("zaosi")
        //println(op2.get)
    
        val v: Int = map1.getOrElse("zaosi",0)
        println(v)//0
    
        val v2: Int = map1.getOrElse("zhaosi",0)
        println(v2)//100
    
        println("==========================")
        //遍历
        //1.通过key
        for(k <- map1.keySet) println(map1(k))
        println("==========================")
        //2.直接遍历value
        for(v <- map1.values) println(v)
        println("==========================")
        //3.通过元组
        for((k,v) <- map1) println(k+":"+v)
        println("==========================")
        //4.函数式的遍历+模式匹配
        map1.foreach{
          case (k,v) => println(k+":"+v)
        }
      }
    }
    
    --------------------------------------------------------------------
    -----------------------java版本-------------------------------------
    --------------------------------------------------------------------
    
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;
    
    public class MapDemo {
        public static void main(String[] args){
            Map<String, Integer> map = new HashMap<>();
            map.put("k1",1);
            map.put("k2",2);
            map.put("k3",3);
            map.put("k4",4);
    
            Set<String> set = map.keySet();
            for (String k : set) {
                System.out.println(map.get(k));
            }
            Collection<Integer> values = map.values();
            for (Integer value : values) {
                System.out.println(value);
            }
            //开发的时候建议使用entrySet
            //因为entrySet拿出来的就是所有的kv,不需要在根据k去找v!!!
            Set<Map.Entry<String, Integer>> entries = map.entrySet();
            for (Map.Entry<String, Integer> entry : entries) {
                System.out.println(entry.getKey() + ":"+entry.getValue());
            }
        }
    }
    
  • 相关阅读:
    一起谈.NET技术,C#调试心经(续) 狼人:
    基于xmpp openfire smack开发之openfire介绍和部署[1]
    mysql学习笔记二
    使用jQuery实现的网页版的个人简历
    基于xmpp openfire smack开发之smack类库介绍和使用[2]
    基于色彩恒常( color constancy)特性的FrankleMcCann Retinex图像增强。
    The import org.cocos2dx.lib cannot be resolved
    C++编译器的递归深度与程序优化思考
    jquery实战视频教程_选项卡效果一
    编译器是怎样工作的?用lex和yacc 写一个计算器(2)
  • 原文地址:https://www.cnblogs.com/-xiaoyu-/p/11407134.html
Copyright © 2020-2023  润新知