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("请输入用户名:\n")
    val password = StdIn.readLine("请输入密码:\n")
    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)

结束

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

猜你喜欢

转载自www.cnblogs.com/boanxin/p/11566530.html