• SCALA-基础知识学习(一)


    概述

    本人开始学习scala的时候,是在使用和开发spark程序的时候,在此为了整理、记录和分享scala的基础知识,我写这篇关于scala的基础知识,希望与广大读者共同学习沟通进步。如果有些代码比较简单,我就略去过分的文字说明。

    SCALA常与句式的使用

    变量的定义:在scala中变量有两个关键字:val和var,val:是不可变的,即不可以在此给其赋值,类似于java中被final修饰的常量,var:是可变的,即可以再次赋值,声明变量的通用格式

       关键字   变量名 :变量的类型=变量值

    val name: String = "wwss"
        var name2: String = "tom"
        val age: Int = 500
    
        //声明变量可以将变量类型省略,scala会根据变量的值自动推断也出变量的类型
        val sex = "男"
    
        //也可以使用Any作为变量的类型,Any类似于java中的Object
        val color: Any = "red"
    
        //可以一次声明多个变量
        val name1, name5, name3, name4: String = "旺财"
    

    for循环:和java类似,

        //使用to方法会产生一个连续不断的区间范围,[0,10]左右两边都包含
        for (i <- 0 to 10)
          println(i)
    
        //使用until方法会产生一个连续不断的区间范围,但是不包含最后一个数字[0,10)
        for (a <- 0 until (10))
          println(a)
    
        //遍历字符串
        for (s <- "abcdfeg")
          println(s)
    
        //多重for循环
        for (i <- 1 to 9; j <- 1 to 9) {
          if (j == 9) {
            println(i + "*" + j + "=" + i * j + "   ")
          } else {
            print(i + "*" + j + "=" + i * j)
          }
        }
    
        //带有if守卫条件的for循环
        for (i <- 0 to 10 if (i % 2 == 0))
          println(i)
    
        //推导式for循环
        val arr = for (i <- 0 to 5) yield i * 2
        for (a <- arr) {
          println(a)
        }
    
        //遍历数组
        val arr2 = Array(1, true, "string")
        for (a <- arr2) {
          println(a)
        }
    
        //中断跳出for循环
        breakable({
          for (i <- 0 to 10) {
            println(i)
            if (i >= 5) {
              break()
            }
          }
        })
    

    if 判断语句:也和java类似

    //在scala中不需要添加分号作为语句块的结束符
        val num = 20
    
        //在scala中if else语句是有返回值的,
        //返回值就是最后一条语句的返回值
        if (num > 20) "zs" else "ls"
        //因为if else 语句是有返回值的,所以可以直接将
        //if else语句赋值给一个变量
    
        //在scala中无论是方法或函数以及条件判断等都只要是有返回值都不需要加return关键字
        val name = if (num > 20) "zs" else "ls"
        println(name)
    
        //如果在if else语句中返回的值类型不一样,scala会自动推断出两者
        //的公共类型,作为变量的类型,any
        val name2 = if (num == 20) "zs" else 100
        println(name2)
    
        //如果if else语句缺省了else语句块,那么其实默认是没有返回值Unit,Unit用"()"表示,
        //类似于java中void
        val name3 = if (num > 20) "zs"
        //和上面的等价
        val name4 = if (num > 20) "zs" else ()
        println(name3)
    

    打印输入输出的格式:

    val name = StdIn.readLine("请输入用户名:
    ")
        val password = StdIn.readLine("请输入密码:
    ")
        if(name.equals("admin") && password.equals("admin")) {
          printf("欢迎您%s登记",name)
        } else {
          println("你输入的用户名或者密码错误,系统自动退出")
        }
    

    while语句格式:

     var num = 0;
        do {
          println(num)
          num += 1
        } while (num <= 5)
    
        //使用break()方法跳出while循环
        var num2 = 0
        breakable({
          while (true) {
            num2 += 1
            if (num2 > 5) {
              break()
            }
            println(num2)
          }
        })
    
        var flag = true
        var num3 = 0
        while (flag) {
          num3 += 1
          if (num3 > 10) {
            flag = false
          }
          println(num3)
        }
    

    SCALA方法和函数的使用

     在scala比较正规的解释是:

    Scala 有方法与函数,二者在语义上的区别很小。Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变量。换句话来说在类中定义的函数即是方法。

    Scala 中的方法跟 Java 的类似,方法是组成类的一部分。

    Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了 Trait 的类的对象。

    定义函数的关键字是:val

    定义函数的通用格式:val  函数名=(参数列表)={函数体}

     //通用的定义格式
      val f1 = (x: Int, y: Int) => {
        x + y
      }
    
      //先定义函数的参数列表类型,具体的函数参数在函数体中定义
      val f2: (Int, Int, Int) => Int = {
        (x, y, z) => {
          x + y + z
        }
      }
    

    定义方法的关键字是:def

    定义方法的通用格式:关键字  方法名(参数列表) :方法的返回值类型={方法体}

    //方法的返回值不需要使用return关键字,同时方法的最后一条语句的返回
      //值作为整个方法的返回值,
      //注意:如果一个方法 的返回值,那么方法 的最后一条语句的返回值一定要和方法 的返回值类型保持一致
      def m1(x: Int, y: Int): Int = {
        var a = 1
        a += 2
        x + y
      }
    
      //可以省略掉方法的返回值类型,scala会自动根据最后一条语句的返回值推断出方法的返回值类型
      def m2(x: Int, y: Int) = {
        x + y
      }
    
      //如果方法没有返回值,可以使用Unit来表示标注,表现为“()”,类似于java中的void
      def m3(x: Int, y: Int): Unit = {
        x + y
      }
    
      //也是没有返回值的方法,在参数列表括号后面直接添加方法体括号,我们称这种方法为过程
      def m3_3(x: Int, y: Int) {
        println(x + y)
      }
    
      //先定义方法参数列表类型,具体的参数名称在方法体中
      def m4: (Int, Int, Int) => Int = {
        (x, y, z) => {
          x + y + z
        }
      }
    
      //柯理化
      def m5(x: Int)(y: Int) = {
        x + y
      }
    
      //柯理化
      def m6(x: Int) = (y: Int) => {
        x + y
      }
    
      //如果定义一个方法,后面方法名称后面的参数列表为空,那么在调用的时候可以加括号,也可以不加括号
      def m7() = {
        println("hello world")
      }
    
      //如果定义一个方法,方法没有参数列表,那么在调用的时候也不能加括号,否则编译不通过
      def m8 = {
        println("hello scala")
      }
    
    
      //递归方法要求我们必须写明方法的返回值类型,不能省略掉,否则报错
      def m9(num: Int): Int = {
        if (num <= 0) 0 else m9(num - 1)
      }
    
      //当参数个数不固定时,那么这时候可以将参数定义为可变参数,可变参数要求是方法的最后一个参数
      def m10(name: String, nums: Int*): Unit = {
        var sum = 0
        for (num <- nums) {
          sum += num
        }
        println(name + "=" + sum)
      }
    
      //在scala中,有时我们调用某些方法时,不希望给出参数的具体值,而希望使用参数自身默认的值
      //此时就定义方法时使用默认参数
      //在调用方法的时候,赋值是从左向右依次赋值,所以说需要把没有默认值的放在最前面
      def m11(age: Int, name: String = "旺财", sex: String = "男") = {
        println(name + "=" + age + "=" + sex)
      }
    

    函数和方法的区别:

    1,方法中的参数列表是可选的,即:参数列表可以没有,也可以为空。比如:方法可以这样写  def me() = 10 ; def me = 10 ;

    但是对于函数来说,参数列表是强制的,即:参数列表可以为空,但不能没有。比如:val f=()=>10这里的括号不能省略。

    2,参数传递,函数是可以作为参数传递,函数名只是代表函数自身;方法不能作为参数传递,用的方法名的地方意味这调用,那为什么在需要函数出现的地方我们可以提供一个方法,在scala中很多高级函数,如map(),filter()等,都是要求提供一个函数作为参数。但是为什么我们可以提供一个方法呢,比如这样:val myList = List(3,56,1,4,72)。

    这是因为,如果期望出现函数的地方我们提供了一个方法的话,该方法就会自动被转换成函数。

    3,方法可以作为一个表达式的一部分出现(调用函数并传参),但是方法(带参方法)不能作为最终的表达式,但是函数可以作为最终的表达式出现。

    scala> //定义一个方法
    
    scala> def m(x:Int) = 2*x
    m: (x: Int)Int
    
    scala> //定义一个函数
    
    scala> val f = (x:Int) => 2*x
    f: Int => Int = <function1>
    
    scala> //方法不能作为最终表达式出现
    
    scala> m
    <console>:9: error: missing arguments for method m;
    follow this method with `_‘ if you want to treat it as a partially applied function
                  m
                  ^
    
    scala> //函数可以作为最终表达式出现
    
    scala> f
    res9: Int => Int = <function1>
    

    方法转换函数的方法:

    在scala中方法可以转换为函数,有两种转换方法,

    1,下划线:方法名 _

    2,scala会隐式转换,不需要手动转换。

    def m1(x: Int, y: Int) = {
        x + y
      }
    
      //
      /**
        * m2接收三个参数,
        *
        * @param f 它是一个函数,接收两个参数,返回值是Int类型,在传入这个参数时,
        *          传入进来的参数必须符合函数的签名
        * @param y 普通参数
        * @param x 普通参数
        * @return
        */
      def m2(f: (Int, Int) => Int, y: Int, x: Int) = {
        f(x, y)
      }
    
      def main(args: Array[String]): Unit = {
        //通过下划线将方法转换成函数
        val f1 = m1 _
        println(f1)
    
        //scala会自动进行转换
        val v2 = m2(m1, 1, 2)
        println(v2)
    
        val foreachFunction = (x: Int) => {
          println(x)
        }
    
        val arr = Array(1, 2, 3, 4, 5)
        arr.foreach(foreachFunction)
    
        arr.foreach((x: Int) => {
          println(x)
        })
    
        arr.foreach((x) => println(x))
    
        arr.foreach(println(_))
    
        println("********************")
        val filterFunction = (x: Int) => {
          x > 3
        }
        arr.filter(filterFunction).foreach((x: Int) => println(x))
    
      }
    

    SCALA常用数据结构

    数组 Array

    在scala 中数组分为不可变长数组(在immutable包下)和可变长数组(在mutable包下),不可变是指长度不可变,但是数组中角标元素的值是可变的,可变长数组是指长度和角标对应的元素的值都是可变的。

    /**
          * 不可变数组(一旦初  始化了,数组的长度是不可变的)
          */
        val arr = Array[Int](1, 2, 3, 4, 5)
    
        //如果一个数组中,有不同类型的元素,那么这个数组的类型是这些元素的公共类型Any
        val arr2: Array[Any] = Array("true", 1, true, "aaa")
    
        //创建一个数组,给数组初始化了长度为5,每个角标的初始值和泛型的初始值一致,也就是0
        val arr3 = new Array[Int](5)
        //创建一个数组,数组的长度是1,这个元素的值是5
        val arr4 = Array(5)
    
        //++运算符是将两个数组添加到新的数组中去,原来的数组并没有改变,只是形成了一个新的数组
        val arr5 = arr ++ arr4
    
    
        /**
          * 可变长数组
          */
        val buffer1 = ArrayBuffer[Int]()
        //如果是+=符号,那么后面只能跟单个元素
        buffer1 += 1
        buffer1 += 2
        //++=后面不能添加单个元素,只能添加数组集合
        buffer1 ++= Array(7, 8, 9)
        buffer1 ++= ArrayBuffer(1, 2, 3, 4, 5, 6)
        //这种添加方式是错误,
        //buffer1(12) = 10   //这种方式是修改角标元素的值,不是添加值
    
        buffer1.append(10, 11, 12)
    
        buffer1 -= 1
        buffer1 -= 2
        buffer1 --= Array(1, 2, 3, 4)
    
        //移除下标为5的对应的元素
        buffer1.remove(5)
        //从指定角标开始,移除指定个数的元素
        buffer1.remove(1, 2)
    
        println(buffer1)
    
    
        /**
          * 数组的常用方法
          */
        val array = Array(1, 2, 3, 4, 5)
    
        //最大值
        println(array.max)
        //最小值
        println(array.min)
        //mkString 拼接
        println(array.mkString)
    
        println(array.mkString(","))
    
        println(array.mkString("[", ",", "]"))
    
        //reverse相当于将数组反转
        println(array.reverse.toBuffer)
    
    
    
    
        /**
          * 数组的转换操作
          */
        val intArr = Array(1, 2, 3, 4, 5, 6)
    
        intArr
          .map((x: Int) => x * 2)
          .sortBy((x: Int) => x) //从小到大排序,即升序
          .reverse //将数组反转
          .foreach((x: Int) => println(x))
    
        println("************")
        intArr.map(_ * 2).sortBy(x => x).reverse.foreach(println(_))
    
        val strArr = Array("hello you", "hello me")
    
        strArr
          //Array(Array("hello","you"),Array("hello","me"))-->Array(hello,you,hello,me)
          .map(x => {
          val fields = x.split(" ")
          fields
        })
          //Array(hello,you,hello,me)
          .flatten
          .foreach(println(_))
    
        println("***************")
        strArr.flatMap((x: String) => x.split(" ")).foreach(println(_))
    
      }
    

    序列

    序列分为可变长序列和不可变长的,序列就是List,底层是链表结构,特点:插入有序,可重复,增加和移除元素很快,查询慢,不可变长序列:List。 可变长序列:ListBuffer

    /**
          * 不可变长序列List,长度不可变,角标元素也不可变
          */
        val list0 = List(1, 2, 3, 4, 5)
    
        //++并没有改变原有的list,只是将两个list序列进行合并形成一个新的list
        val list1 = list0 ++ List(6, 7, 8, 9)
        println(list1.toBuffer)
        println(list0.toBuffer)
    
        println("#####################")
    
        /**
          * 定义可变长度序列
          */
        val lb0 = ListBuffer(1, 2)
        //+=或-=后面只能跟一个单个的元素
        lb0 += 3
        lb0 -= 3
        //++=或--=后面只能跟一个序列list或者listbuffer
        lb0 ++= List(4, 5, 6)
        lb0 --= List(4, 5)
        lb0 ++= ListBuffer(8, 9, 10)
        lb0.append(11, 12)
    
        //移除指定角标的元素
        lb0.remove(0)
        //从指定角标开始,移除指定个数的元素
        lb0.remove(1, 2)
    
        println(lb0)
    
    
        println("****************ccccc************")
        /**
          * 给list头部添加元素
          */
        val list01 = List(4, 5, 6);
        //注意,这里并不是将元素添加到list01里面,而是将list01和后面的元素(1,2,3)进行合并 ,然后形成一个新的list
        //newList,需要注意的是后面的(1,2,3)是作为一个整体和list01进行合并
        var newList = list01.::(1, 2, 3)
        println(newList)
        println(list01)
        newList = list01.+:(1, 2, 3)
        println(newList)
    
        newList = (1, 2, 3) :: list0
        println(newList)
    
        newList = (1, 2, 3) +: list01
        println(newList)
    
        //这里是将1,2,3进行拆分开同list01进行合并
        newList = List(1, 2, 3) ++ list01
        println(newList)
    
        println("$$$$$$$$$$$$$$$$$$$$$$")
    
        /**
          * 给list尾部添加元素
          */
        val list02 = List(4, 5, 6)
        //这里也是将(7,8,9)作为整体同list02进行合并 添加到尾部,形成一个新的list
        var newList02 = list02.:+(7, 8, 9)
        println(newList02)
    
        //将7,8,9进行拆分同list02进行合并插入到list02后面去,形成一个新的list,原来的list并没有改变
        newList02 = list02 ++ List(7, 8, 9)
        println(newList02)
    
    
        /**
          * 序列的常用操作方法
          */
        val lt = List(1, 2, 3, 4, 5)
        //求和
        println(lt.sum)
        //最大值
        println(lt.max)
        //最小值
        println(lt.min)
        //第一人元素
        println(lt.head)
        //最后一个元素
        println(lt.last)
        //反转序列形成一个新的list,原来的list不会被改变
        println(lt.reverse)
        //拼接
        println(lt.mkString)
        println(lt.mkString(","))
        println(lt.mkString("[", ",", "]"))
    
    
        /**
          * 序列的转换操作
          */
        val lit = List(1, 2, 3, 4, 5, 6, 6,7,7, 8)
        lit.map(_ * 2).filter(x => x > 10).distinct.reverse.foreach(println(_))
    

    map的使用:map分为可变长和不可变长

     /**
          * 不可变长Map映射,长度和值一旦初始化后不能再次被改变
          */
    
        //通过对偶元组的方法创建映射
        val map0 = Map(("a", "A"), ("b", "B"), ("c", "C"))
        // 通过箭头方式创建Map映射
        val map1 = Map("a" -> "A", "b" -> "B", "c" -> "C")
        //两者进行混合创建Map映射
        val map3 = Map("a" -> "A", ("b", "B"), ("c", "C"))
    
        //++只是将两个映射合并形成新的map映射,原有的map映射并没有改变
        val newMap = map0 ++ map1
        println(newMap)
    
    
        /**
          * 可变长map映射,mutable包下
          */
    
        val map4 = mutable.Map("a" -> "A")
        map4.put("b", "B")
        map4 += ("c" -> "C", "d" -> "D")
        map4 += (("e", "E"), ("f", "F"))
        map4 ++= mutable.Map("j" -> "J", "h" -> "H", ("i", "I"))
        println(map4)
    
        /**
          * 移除map中的key
          */
        map4 -= "i"
        println(map4)
        map4 --= Set("i", "j", "f")
        println(map4)
        map4.remove("h")
        println(map4)
    
    
        /**
          * Map映射常用操作方法
          */
        //判断一个key是否存在,存在返回true,否则返回false
        println(map4.contains("a"))
        //获取key对应的值,注意如果通过map("Key")获取对应的值,应该进行key是否存在判断
        if (map4.contains("e")) {
          println(map4("e"))
        }
    
        //映射的get方法也是用来获取key对应的值,但是这个方法返回的是一个option对象,这个option对象有两个
        //子类,如果有key则返回Some(some对象中封装了key对应的值,可以通过Some的get方法获取值)对象,没有key则返回None对象
        println(map4.get("e").get)
        val value: Option[String] = map4.get("e")
        //isEmpty方法可以用来判断是Some对象还是None
        if (!value.isEmpty) {
          println(value.get)
        } else {
          println(value)
        }
    
    
        //如果key存在,则返回key对应的value,否则返回给定的默认值
        val v = map4.getOrElse("e", "EE")
        println(v)
    
    
    
        println("********************************")
        /**
          * LinkedHashMap 插入有序,会按照我们的插入顺序排序,因为底层是链表结构
          */
        val map5 = mutable.LinkedHashMap[String, String]()
        map5 += ("d" -> "D")
        map5 += (("a", "A"))
        map5("c") = "C"
        map5("b") = "B"
        println(map5)
    
        /**
          * SortedMap可以自动对Map的key进行排序
          */
        val map6 = mutable.SortedMap[String, String]()
        map6("c") = "C"
        map6("b") = "B"
        map6("a") = "A"
        println(map6)
    

    set集合

    特点和java一样无顺序不重复

    /**
          * 不可变长set集合
          */
        val set0 = Set(1, 2, 3, 4, 5)
        //++并没改变原有的set集合,只是将两个set进行合并形成新的set集合
        val newSet0 = set0 ++ Set(6, 7, 8, 9)
        println(newSet0)
    
    
        /**
          * 可变长set集合
          */
        val set1 = mutable.Set(1, 3)
        //+=或-=后面只能是半单个元素
        set1 += 1
        set1 += 2
        //++=或者 --=后面只能添加set集合
        set1 ++= mutable.Set(5, 6, 7)
        set1.add(12)
        println(set1)
    
        set1 -= 1
        set1 --= mutable.Set(1, 2, 3)
        println(set1)
    
    
        /**
          * set常用操作方法
          */
        println(set1.mkString(","))
        println(set1.size)
        println(set1.head)
        println(set1.last)
        println(set1.max)
        println(set1.min)
        println(set1.sum)
    
    
        /**
          * set的转换操作
          */
        set1.map(_ * 2).filter(x => x > 2).foreach(println(_))
    

    元组的使用

    scala的元组是用括号来表示的,获取元组的值用下划线来表示,角标从1开始。

    //定义一个元组
        val t1 = ("小明", "男", 25)
        //元组的下标是从1开始
        println(t1._1 + "=" + t1._2 + "=" + t1._3)
    
        //只有两个元素的元组被称之为对偶元组(key-value)
        val tuple2 = ("id", "123")
        println(tuple2._1 + "-" + tuple2._2)
    
        //可以将元组中的元素单独赋值给对应的变量
        val tuple3, (name, age, sex) = ("ximing", 12, "男")
        println(tuple3)
        println(name)
        println(age)
        println(sex)
    
        //数组的拉链操作转换成元组,如果数组中有多余的就会被舍弃掉
        val arr1 = Array("a", "b", "c", "d","e")
        val arr2 = Array("A", "B", "C", "D")
    
        val arr3: Array[(String, String)] = arr1.zip(arr2)
        println(arr3.toBuffer)
    

    结束

    本文没什么技术含量,只是闲暇是对自己知识的反复练习和记录。希望对读者有溢。

  • 相关阅读:
    HTML <iframe> 标签
    HTML <tr> 标签
    HTML <img> 标签的 border 属性
    jQuery ajax ajax() 方法
    CSS padding 属性
    SQL Server CONVERT() 函数
    CSS overflow 属性
    HTML <input> 标签
    Java动态代理一——动态类Proxy的使用
    Java拆箱装箱小结
  • 原文地址:https://www.cnblogs.com/boanxin/p/11566530.html
Copyright © 2020-2023  润新知