Scala

关注公众号 jb51net

关闭
首页 > 软件编程 > Scala > Scala基础语法详解

Scala基础语法总结

投稿:wdc

这篇文章主要介绍了Scala基础语法总结,需要的朋友可以参考下

一、变量

val/var 变量名称:变量类型 = 初始值

注意:

 惰性变量

lazy val 变量名 = 表达式

 二、数据类型

基础类型类型说明
Byte8位带符号整数
Short16位带符号整数
Int32位带符号整数
Long64位带符号整数
Char16位无符号Unicode字符
StringChar类型的序列(字符串)
Float32位单精度浮点数
Double64位双精度浮点数
Booleantrue或false

1. scala中所有的类型都使用大写字母开头,说明是它是“类”
2. 整形使用Int而不是Integer
3. scala中定义变量可以不写类型,让scala编译器自动推断 

三、scala中的条件表达式

1、if表达式

这个和java差不多,可以加括号,或者不加括号

  def main(args: Array[String]): Unit = {
     val x:Int=2
     if (x>10) println(x)
     else println(x+x)
}

打印为2

2、块表达式

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

  def main(args: Array[String]): Unit = {

    val x = 0
    val result = {
      val y = x + 10
      val z = y + "-hello"
      val m = z + "-kaikeba"
      "over"
    }
    println(result)
}

打印结果

over

Process finished with exit code 0

返回值就是m了 

  def main(args: Array[String]): Unit = {
    val x = 0
    val result = {
      val y = x + 10
      val z = y + "-hello"
      val m = z + "-kaikeba"
      m
    }
    println(result)
}

打印结果

10-hello-kaikeba

四、循环

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

for (i <- 表达式/数组/集合){
    //表达式
}

1、简单for循环

def main(args: Array[String]): Unit = {
    var nums=1 to 10
    //for循环
    for(i <- nums) println(i)
}

2、双层for循环

  def main(args: Array[String]): Unit = {

    //双层for循环
    for (i <- 1 to 3; j <- 1 to 3)
      println(i * 10 + j)
}

打印的值为

11
12
13
21
22
23
31
32
33

3、守卫:在for表达式中可以添加if判断语句,这个if判断称为守卫

 def main(args: Array[String]): Unit = {
//    守卫
    var nums = 1 to 10
    for (i <- nums if i>5 ) println(i)
}

打印的值为: 

6
7
8
9
10

4、yield表达式 

在for循环体中,以yield表达式开始,这类循环能构建出一个新的集合,我们把这类循环称为推导式

def main(args: Array[String]): Unit = {

    // for推导式:for表达式中以yield开始,该for表达式会构建出一个集合
    val v = for(i <- 1 to 5) yield i * 10
    //打印集合v的第一个元素
    println(v(0))
}

打印的值为

10

五、while循环

while(返回值为布尔类型的表达式){
    //表达式
}

六、方法

def methodName (参数名:参数类型, 参数名:参数类型) : [return type] = {
    // 方法体:一系列的代码
}
  //方法一
  def yy(i: Int = 10, u: Int = 8): Int = {
    return i + u;
  }

  //方法二
  def tt(i: Int) = i * i


  /**
   * 递归必须添加返回值参数
   *
   * @param x
   * @return
   */
  //方法三
  def m1(x: Int): Int = {
    if (x == 1) 1
    else x * m1(x - 1)
  }

  /**
   * 参数值加*,可以传递多个参数
   *
   * @param num
   * @return
   */
  //    方法四
  def add(num: Int*) = num.sum

  def main(args: Array[String]): Unit = {
    
        println(yy(1))
        println(tt(8))
        println(m1(10))
        println(add(1,2,3))
}

打印的值为

9
64
3628800
6

6、函数

val 函数变量名 = (参数名:参数类型, 参数名:参数类型....) => 函数体

注意

 val add2 = (x: Int, y: Int) => x * y
  def main(args: Array[String]): Unit = {
        println(add2(2,4))
}

 打印的值为

8

方法和函数的区别

方法转换为函数

(1)、定长数组

demo如下 

def main(args: Array[String]): Unit = {
    val a = new Array[Int](10)
    println(a)
    a(0)=98
    println(a(0))
    println(a(1))
    println(a.length)
  }

 打印的值为:

[I@ea4a92b
98
0
10

(2)、变长数组

import scala.collection.mutable.ArrayBuffer

语法

demo如下 

  def main(args: Array[String]): Unit = {
    //变长数组
    val a = ArrayBuffer[String]();
    a+=("test")
    a+=("张三")
    a++=Array("妞儿","所以算是")
    println(a(3))
    println(a.size)
  }
}

打印的值为

所以算是
4

(3)、遍历数组

可以使用以下两种方式来遍历数组:

for(i <- a) println(i)
/0 to n    ——包含0,也包含n
for(i <- 0 to a.length -1 ) println(a(i))
//0 until n ——生成一系列的数字,包含0,不包含n
for(i <- 0 until a.length) println(a(i))

(4)、数组常用操作

scala中的数组封装了丰富的计算操作,将来在对数据处理的时候,不需要我们自己再重新实现。

 def main(args: Array[String]): Unit = {

    val array = Array(1,3,4,2,5)
    println("求和:"+array.sum)
    println("最大值:"+array.max)
    println("最小值:"+array.min)
    println("排序(获取一个新数组,并翻转):"+array.sorted.reverse(0))

  }

 打印如下

求和:15
最大值:5
最小值:1
排序(获取一个新数组,并翻转):5

8、元组 

元组可以用来包含一组不同类型的值。例如:姓名,年龄,性别,出生年月。

元组的元素是不可变的。

1、定义元组

使用括号来定义元组

val/var 元组变量名称 = (元素1, 元素2, 元素3....)

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

val/var 元组 = 元素1 -> 元素2

2、访问元组

  def main(args: Array[String]): Unit = {
    val a = (1, "张三", 20, "北京市")
    val b = 1 -> 2
    println(a._1)
    println(a._4)
    println(b._1)
  }

 打印的值为

1
北京市
1

9、映射Map

(1)、不可变map

  定义语法

val/var map = Map(键->值, 键->值, 键->值...)    // 推荐这种写法,可读性更好 
val/var map = Map((键, 值), (键, 值), (键, 值), (键, 值)...)
def main(args: Array[String]): Unit = {
    val map1 = Map("zhangsan"->30, "lisi"->40)
    val map2 = Map(("zhangsan", 30), ("lisi", 30))
    println(map1("lisi"))
    println(map2("zhangsan"))
  }

打印的值为

40
30

(2)、可变Map

1、导包

import scala.collection.mutable.Map
  def main(args: Array[String]): Unit = {

    val map3 = Map("zhangsan" -> 30, "lisi" -> 40)
    //修改一个
    map3("zhangsan") = 50
    println("修改的" + map3)
    //添加一个
    map3 += ("yy" -> 22)
    println("添加的" + map3)
    //删去一个
    map3 -= "yy"
    println("删除的" + map3)
    //拿取到map所有key
    println("拿取到map所有key:" + map3.keys)
    println("拿取到map所有key:" + map3.keySet)
    //获取所有的value
    println("获取所有的value:" + map3.values)
  }

打印的值为: 

修改的Map(lisi -> 40, zhangsan -> 50)
添加的Map(yy -> 22, lisi -> 40, zhangsan -> 50)
删除的Map(lisi -> 40, zhangsan -> 50)
拿取到map所有key:Set(lisi, zhangsan)
拿取到map所有key:Set(lisi, zhangsan)
获取所有的value:HashMap(40, 50)

(3)、遍历Map

     val map3 = Map("zhangsan" -> 30, "lisi" -> 40)
    //方法一。通过遍历key拿取到值
    for (i <- map3.keys) println(i + "->" + map3(i))
    //方法二,通过元组的方法拿取到值
    for (i <- map3) println(i._1 + "->" + i._2)
    //方法三
    for((k, v) <- map3) println(k + " -> " + v)
lisi->40
zhangsan->30
lisi->40
zhangsan->30
lisi -> 40
zhangsan -> 30

10、Set集合

不可变set集合 

//创建一个空的不可变集
val/var 变量名 = Set[类型]()

//给定元素来创建一个不可变集
val/var 变量名 = Set[类型](元素1, 元素2, 元素3...)
 def main(args: Array[String]): Unit = {
    val a = Set(1, 1, 2, 3, 4, 5)
    println("a的长度大小"+a.size)
    for(i<-a)println(i)
    println("添加一个元素的新set:",a + 6)
    println("删除一个元素的新set:",a -1)
    println("删除多个元素的新set:",a -- Set(2,3) )
    println("添加多个元素的新set:",a ++ Set(6,7,8)  )
    println("多个Set集合交集的新set:",a & Set(3,4,5,6))
    println(a)
  }

打印如下:

a的长度大小5
5
1
2
3
4
(添加一个元素的新set:,Set(5, 1, 6, 2, 3, 4))
(删除一个元素的新set:,Set(5, 2, 3, 4))
(删除多个元素的新set:,Set(5, 1, 4))
(添加多个元素的新set:,Set(5, 1, 6, 2, 7, 3, 8, 4))
(多个Set集合交集的新set:,Set(5, 3, 4))
Set(5, 1, 2, 3, 4)

注意:这里对不可变的set集合进行添加删除等操作,对于该集合来说是没有发生任何变化,这里是生成了新的集合,新的集合相比于原来的集合来说发生了变化

可变Set集合

要使用可变集,必须要手动导入:

import scala.collection.mutable.Set

11、列表 List

val/var 变量名 = List(元素1, 元素2, 元素3...)

//使用 Nil 创建一个不可变的空列表
val/var 变量名 = Nil

//使用 :: 方法创建一个不可变列表
val/var 变量名 = 元素1 :: 元素2 :: Nil
 def main(args: Array[String]): Unit = {
    val list1 = List(1, 2, 3, 4)
    val list2 = Nil
    val list3= 1::2::3::Nil
    println(list1(0))
    println(list3)
  }

 打印的值为

1
List(1, 2, 3)

可变列表

1、使用ListBuffer元素类型 创建空的可变列表,语法结构

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

2、使用ListBuffer(元素1, 元素2, 元素3...)创建可变列表,语法结构

val/var 变量名 = ListBuffer(元素1,元素2,元素3...)
    val a = ListBuffer[Int]()
    val b = ListBuffer(1, 2, 3, 4)
    println(b(0))
    println("list数组首部:", b.head)
    println("获取除了第一个元素外其他元素组成的列表", b.tail)
    b += 5
    println("添加应元素", b)
    b ++= List(6, 7)
    println("添加一个不可变列表", b)
    b ++= ListBuffer(8, 9)
    println("添加一个可变列表", b)
    b -= 9
    println("删除单个元素", b)
    b --= List(7,8)
    println("删除一个不可变的列表存在的元素", b)
    b --= ListBuffer(5,6)
    println("删除一个可变的列表存在的元素", b)
    println("toList根据可变的列表生成一个不可变列表",b.toList)
    println("toList根据可变的列表生成一个不可变列表,原列表不变",b)

    println("toArray根据可变的列表生成一个新的不可变数组",b.toArray)
    println("toArray根据可变的列表生成一个新的不可变数组,原列表不变",b)

打印如下

1
(list数组首部:,1)
(获取除了第一个元素外其他元素组成的列表,ListBuffer(2, 3, 4))
(添加应元素,ListBuffer(1, 2, 3, 4, 5))
(添加一个不可变列表,ListBuffer(1, 2, 3, 4, 5, 6, 7))
(添加一个可变列表,ListBuffer(1, 2, 3, 4, 5, 6, 7, 8, 9))
(删除单个元素,ListBuffer(1, 2, 3, 4, 5, 6, 7, 8))
(删除一个不可变的列表存在的元素,ListBuffer(1, 2, 3, 4, 5, 6))
(删除一个可变的列表存在的元素,ListBuffer(1, 2, 3, 4))
(toList根据可变的列表生成一个不可变列表,List(1, 2, 3, 4))
(toList根据可变的列表生成一个不可变列表,原列表不变,ListBuffer(1, 2, 3, 4))
(toArray根据可变的列表生成一个新的不可变数组,[I@3567135c)
(toArray根据可变的列表生成一个新的不可变数组,原列表不变,ListBuffer(1, 2, 3, 4))

12、函数式编程

(1)、遍历 - foreach

方法描述

foreach(f: (A) ⇒ Unit): Unit
foreachAPI说明
参数f: (A) ⇒ Unit接收一个函数对象作为参数 函数的输入参数为集合的元素 返回值为空
返回值Unit
  def main(args: Array[String]): Unit = {
    val list = List(1, 2, 3, 4)
    //定义一个匿名函数传入到foreach方法中
    list.foreach((u: Int) => println(u))
    //匿名函数的输入参数类型可以省略,由编译器自动推断
    list.foreach(u => println(u))
    //  当函数参数,只在函数体中出现一次,而且函数体没有嵌套调用时,可以使用下划线来简化函数定义
    list.foreach(println(_))
    //最简单直接
    list.foreach(println)
  }

(2)、映射 - map

def map[B](f: (A) ⇒ B): TraversableOnce[B]
ap方法API说明
泛型[B]指定map方法最终返回的集合泛型
参数f: (A) ⇒ B传入一个函数对象作为参数 该函数接收一个类型A(要转换的集合的元素类型) 返回值为类型B
返回值TraversableOnce[B]B类型的集合

    val list = List(1, 2, 3, 4)
    //定义一个匿名函数
    val b=list.map((i:Int)=>i*10)
    println(b)
    //省略匿名函数参数类型
    val c=list.map(i=>i*10)
    println(c)
    //最简单用下划线的方法
    val d=  list.map(_ * 10)
    println(d)

打印结果如下

List(10, 20, 30, 40)
List(10, 20, 30, 40)
List(10, 20, 30, 40)

(3)、扁平化映射 - flatmap

def flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): TraversableOnce[B]

方法说明  

flatmap方法API说明
泛型[B]最终要转换的集合元素类型
参数f: (A) ⇒ GenTraversableOnce[B]传入一个函数对象作为参数 函数的参数是集合的元素 函数的返回值是一个集合
返回值TraversableOnce[B]B类型的集合

def main(args: Array[String]): Unit = {
    val list = List("hadoop hive spark flink", "hbase spark")
    val tt = list.flatMap(x => x.split(" "));
    println(tt)
    //简写
    val t2 = list.flatMap(_.split(" "))
    println(t2)
    //flatMap该方法其本质是先进行了map 然后又调用了flatten
    val t3 = list.map(_.split(" ")).flatten
    println(t3)
  }

打印结果如下

List(hadoop, hive, spark, flink, hbase, spark)
List(hadoop, hive, spark, flink, hbase, spark)
List(hadoop, hive, spark, flink, hbase, spark)

(4)、过滤 - filter

def filter(p: (A) ⇒ Boolean): TraversableOnce[A]

 方法说明

filter方法API说明
参数p: (A) ⇒ Boolean传入一个函数对象作为参数 函数的参数是集合中的元素 此函数返回布尔类型,满足条件返回true, 不满足返回false
返回值TraversableOnce[A]列表

 demo展示

def main(args: Array[String]): Unit = {
    val list = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    ///过滤出集合中大于5的元素
    val tt=list.filter(x=>x>5)
    println(tt)
    //把集合中大于5的元素取出来乘以10生成一个新的list集合
    val t3=list.filter(x=>x>5).map(u=>u*10)
    println(t3)
  }

 打印的值为:

List(6, 7, 8, 9, 10)
List(60, 70, 80, 90, 100)

(5) 、分组 - groupBy

def groupBy[K](f: (A) ⇒ K): Map[K, List[A]] 

groupBy方法API说明
泛型[K]分组字段的类型
参数f: (A) ⇒ K传入一个函数对象 接收集合元素类型的参数 返回一个K类型的key,这个key会用来进行分组,相同的key放在一组中
返回值Map[K, List[A]]返回一个映射,K为分组字段,List为这个分组字段对应的一组数据

scala> val a = List("张三"->"男", "李四"->"女", "王五"->"男")
a: List[(String, String)] = List((张三,男), (李四,女), (王五,男))

// 按照性别分组
scala> a.groupBy(_._2)
res0: scala.collection.immutable.Map[String,List[(String, String)]] = Map(男 -> List((张三,男), (王五,男)),
女 -> List((李四,女)))

// 将分组后的映射转换为性别/人数元组列表
scala> res0.map(x => x._1 -> x._2.size)
res3: scala.collection.immutable.Map[String,Int] = Map(男 -> 2, 女 -> 1)

//根据这个例子,思考下,作业中如何使用scala编程,实现词频统计?
 

//求每个省份有多少人?
val b = List("张三"->("男", "北京"), "李四"->("女", "河北"), "王五"->("男", "北京"))

scala> b.groupBy(_._2._2).map(x => (x._1, x._2.size))
res14: scala.collection.immutable.Map[String,Int] = Map(北京 -> 2, 河北 -> 1)

object yyy {
  def main(args: Array[String]): Unit = {
   val a = List("张三"->"男", "李四"->"女", "王五"->"男")
    println(a.groupBy(_._2))

    val list2 =List("a,b,c","y,c,a,e,a,c,a")
    var map=list2.flatMap(x=>x.split(",")).groupBy(x=>x).map(y=>(y._1,y._2.size));
    println(map)
    println("a的个数是:"+map("a"))
  }
}

打印的值为 

Map(男 -> List((张三,男), (王五,男)), 女 -> List((李四,女)))
Map(e -> 1, y -> 1, a -> 4, b -> 1, c -> 3)
a的个数是:4

(6)、排序 - sort

在scala集合中,可以使用以下几种方式来进行排序

sorted默认排序

 def main(args: Array[String]): Unit = {
    val list = List(5, 1, 2, 4, 3)
    println(list.sorted)
  }
List(1, 2, 3, 4, 5)

sortBy指定字段排序

def sortBy[B](f: (A) ⇒ B): List[A]
sortBy方法API说明
泛型[B]按照什么类型来进行排序
参数f: (A) ⇒ B传入函数对象作为参数 函数接收一个集合类型的元素为参数 返回B类型的元素进行排序
返回值List[A]返回排序后的列表

结果如下: 

 val list2 = List("1 hadoop", "2 spark", "3 flink")
    println(list2.sortBy(x=>x.split(" ")(0)))

打印的结果如下: 

List(1 hadoop, 2 spark, 3 flink)

sortWith自定义排序  

def sortWith(lt: (A, A) ⇒ Boolean): List[A]
sortWith方法API说明
参数lt: (A, A) ⇒ Boolean传入一个比较大小的函数对象作为参数 函数接收两个集合类型的元素作为参数 返回两个元素大小,小于返回true,大于返回false
返回值List[A]返回排序后的列表
   val list3 = List(2, 3, 1, 6, 4, 5)
    //降序
    var tt = list3.sortWith((x, y) => x > y)
    println(tt)
    //升序
    var tt2 = list3.sortWith((x, y) => x < y)
    println(tt2)
    //简写
    var tt3 =list3.sortWith(_ > _)
    println(tt3)

 打印的结果:

List(6, 5, 4, 3, 2, 1)
List(1, 2, 3, 4, 5, 6)
List(6, 5, 4, 3, 2, 1)

(5)、聚合 - reduce

def reduce[A1 >: A](op: (A1, A1) ⇒ A1): A1
reduce方法API说明
泛型[A1 >: A](下界)A1必须是集合元素类型的子类
参数op: (A1, A1) ⇒ A1传入函数对象,用来不断进行聚合操作 第一个A1类型参数为:当前聚合后的变量 第二个A1类型参数为:当前要进行聚合的元素
返回值A1列表最终聚合为一个元素
def main(args: Array[String]): Unit = {
    val a = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    //基础的写法
    var b = a.reduce((x, y) => x + y)
    println("基础的写法"+b)
    //简单的写法
    var c = a.reduce(_ + _)
    println("简单的写法"+c)
    //从左往右计算
    var d = a.reduceLeft(_ + _)
    println("从左往右计算"+d)
     //从右往左计算
    var f = a.reduceRight(_ + _)
    println("从右往左计算"+f)
  }
基础的写法55
简单的写法55
从左往右计算55
从右往左计算55

(6)、折叠 - fold

fold与reduce很像,但是多了一个指定初始值参数

def fold[A1 >: A](z: A1)(op: (A1, A1) ⇒ A1): A1
reduce方法API说明
泛型[A1 >: A](下界)A1必须是集合元素类型的子类
参数1z: A1初始值
参数2op: (A1, A1) ⇒ A1传入函数对象,用来不断进行折叠操作 第一个A1类型参数为:当前折叠后的变量 第二个A1类型参数为:当前要进行折叠的元素
返回值A1列表最终折叠为一个元素
def main(args: Array[String]): Unit = {
    val a = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

    var e = a.fold(0)(_ + _)
    println("简单折叠:",e)
    var g = a.fold(5)(_ + _)
    println("给定一个初始值,,折叠求和:"+g)
    var h=  a.foldLeft(10)(_ + _)
    println("从左往右折叠:",h)

  }
(简单折叠:,55)
给定一个初始值,,折叠求和:60
(从左往右折叠:,65)

13、高阶函数

使用函数值作为参数,或者返回值为函数值的“函数”和“方法”,均称之为“高阶函数”。

1、函数值作为参数

  def main(args: Array[String]): Unit = {
    //定义一个数组
    val array = Array(1, 2, 3, 4, 5)
    //定义一个函数
    val func = (x: Int) => x * 10
    //函数作为参数传递到方法中
    val tt=  array.map(func)
    println("通过map转化的新数组:",tt)
    println("通过map转化的新数组最大:",tt.max)
  }

打印的值为:

(通过map转化的新数组:,[I@17550481)
(通过map转化的新数组:,50)

2、匿名函数

一个没有名称的函数----匿名函数

 def main(args: Array[String]): Unit = {
    val array = Array(1, 2, 3, 4, 5)
    var a = array.map(x => x * 10)
    println(a.max)
  }

打印的值为: 

50

3、柯里化

方法可以定义多个参数列表,当使用较少的参数列表调用多参数列表的方法时,会产生一个新的函数,该函数接收剩余的参数列表作为其参数。这被称为柯里化。

 def main(args: Array[String]): Unit = {
    def getAddress(a: String): (String, String) => String = {
      (b: String,c: String) => a + "-" + b + "-" + c
    }
    var b=getAddress("china");
    var c=b("beijing","tianAnMen")
    println(c)
  }
china-beijing-tianAnMen

 4、闭包

函数里面引用外面类成员变量叫作闭包

  def main(args: Array[String]): Unit = {
    var factor = 1
    val f1 = (x: Int) => x * factor
    println(f1(8))
    factor=2
    println(f1(8))
  }
8
16

//定义的函数f1,它的返回值是依赖于不在函数作用域的一个变量
//后期必须要要获取到这个变量才能执行
//spark和flink程序的开发中大量的使用到函数,函数的返回值依赖的变量可能都需要进行大量的网络传输获取得到。这里就需要这些变量实现序列化进行网络传输。

 def main(args: Array[String]): Unit = {
   
    def multiply(x: Double) = (y: Double) => x * y

    //先进行科尔化
    val doubleFunc = multiply(2)
    val tripleFunc = multiply(3)
    //    再对闭包进行计算
    var u = doubleFunc(10)
    var u2 = tripleFunc(10)
    println(u)
    println(u2)
  }
20.0
30.0

14、scala面向对象编程之类

1、类的定义

scala是支持面向对象的,也有类和对象的概念。

与java相比,他无需get set方法,就可以对变量进行赋值封装操作 

import java.util.Date

class Customer {
  var name: String = _
  var sex: String = _
  val registerDate: Date = new Date

  def sayHi(msg: String) = {
    println(msg)
  }
}

object Main {
  def main(args: Array[String]): Unit = {
    val customer = new Customer
    //给对象的成员变量赋值
    customer.name = "张三"
    customer.sex = "男"

    println(s"姓名: ${customer.name}, 性别:${customer.sex}, 注册时间: ${customer.registerDate}")
    //对象调用方法
    customer.sayHi("你好!")
  }
}

 打印的结果为:

姓名: 张三, 性别:男, 注册时间: Fri Apr 22 16:23:21 CST 2022
你好!

(1). var name:String = _,  _表示使用默认值进行初始化
   例如:String类型默认值是null,Int类型默认值是0,Boolean类型默认值是false...
(2). val变量不能使用_来进行初始化,因为val是不可变的,所以必须手动指定一个默认值
(3). main方法必须要放在一个scala的object(单例对象)中才能执行

2、类的构造器

主构造器

class 类名(var/val 参数名: 类型 = 默认值, var/val 参数名: 类型 = 默认值){
    // 构造代码块
}

辅助构造器

1、scala中的object

object DateUtils {
//  / 在object中定义的成员变量,相当于Java中定义一个静态变量
  // 定义一个SimpleDateFormat日期时间格式化对象
  val simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm")

  // 构造代码
  println("构造代码")

  // 相当于Java中定义一个静态方法
  def format(date: Date) = simpleDateFormat.format(date)

  // main是一个静态方法,所以必须要写在object中
  def main(args: Array[String]): Unit = {

    println { DateUtils.format(new Date()) };
  }
}

 (1). 使用object 单例对象名定义一个单例对象,可以用object作为工具类或者存放常量
(2). 在单例对象中定义的变量,类似于Java中的static成员变量
(3). 在单例对象中定义的方法,类似于Java中的static方法
(4). object单例对象的构造代码可以直接写在花括号中
(5). 调用单例对象的方法,直接使用单例对象名.方法名,访问单例对象的成员变量也是使用单例对象名.变量名
(6). 单例对象只能有一个无参的主构造器,不能添加其他参数

2、scala中的伴生对象

package com.testScala.E_duixiang

class Dog {
  val id = 1
  private var name = "kkb"
  def printName(): Unit = {
    //在Dog类中可以访问伴生对象Dog的私有属性
    println(Dog.CONSTANT + name )
  }
}

object Dog{
  //伴生对象中的私有属性
  private val CONSTANT = "汪汪汪 : "
  def main(args: Array[String]) {
    val dog = new Dog
    //访问私有的字段name
    dog.name = "123"
    dog.printName()
  }
}
汪汪汪 : 123

(1). 伴生类和伴生对象的名字必须是一样的
(2). 伴生类和伴生对象需要在一个scala源文件中
(3). 伴生类和伴生对象可以互相访问private的属性

3、scala中object的apply方法

package com.testScala.E_duixiang

class Person(var name: String, var age: Int) {

  override def toString = s"Person($name, $age)"
}

object Person {
  // 实现apply方法
  // 返回的是伴生类的对象
  def apply(name: String, age: Int): Person = new Person(name, age)

  // apply方法支持重载
  def apply(name: String): Person = new Person(name, 20)

  def apply(age: Int): Person = new Person("某某某", age)

  def apply(): Person = new Person("某某某", 20)
}

object Main2 {
  def main(args: Array[String]): Unit = {
    val p1 = Person("张三", 20)
    val p2 = Person("李四")
    val p3 = Person(100)
    val p4 = Person()

    println(p1)
    println(p2)
    println(p3)
    println(p4)
  }
}
Person(张三, 20)
Person(李四, 20)
Person(某某某, 100)
Person(某某某, 20)

 (1). 当遇到类名(参数1, 参数2...)会自动调用伴生对象相应的apply方法,在apply方法中来创建对象
(2). 定义apply时,如果参数列表是空,也不能省略括号(),否则引用的是伴生对象

4、scala中object的main方法

object Main1{
  def main(args: Array[String]) = {
    println("hello, scala")
  }
}

16、scala面向对象编程之继承

1、继承extends

class Person3 {
  val name = "super"

  def getName = name
}

class Student3 extends Person3 {
  // 重写val字段
  override val name: String = "child"

  // 重写getName方法
  override def getName: String = "hello, " + super.getName
}

object Main3 {
  def main(args: Array[String]): Unit = {
    val p = new Student3();
    println(p.name)
    println(p.getName)
  }
}
child
hello, child

3、isInstanceOf和asInstanceOf

JavaScala
判断对象是否是C类型obj instanceof Cobj.isInstanceof[C]
将对象强转成C类型(C ) objobj.asInstanceof[C]
获取类型为T的class对象C.classclassOf[C]
class Person4
class Student4 extends Person4

object Main4 {
  def main(args: Array[String]): Unit = {
    val s1: Person4 = new Student4

    // 判断s1是否为Student4类型
    if(s1.isInstanceOf[Student4]) {
      // 将s1转换为Student3类型
      val s2 =  s1.asInstanceOf[Student4]
      println(s2)
    }
  }
}
com.testScala.F_jicheng.Student4@ea4a92b

4、getClass和classOf

isInstanceOf 只能判断出对象是否为指定类以及其子类的对象,而不能精确的判断出,对象就是指定类的对象。如果要求精确地判断出对象就是指定类的对象,那么就只能使用 getClass 和 classOf 。

class Person5
class Student5 extends Person5

object Student5{
  def main(args: Array[String]) {
    val p: Person5 = new Student5
    //判断p是否为Person5类的实例
    println(p.isInstanceOf[Person5])//true

    //判断p的类型是否为Person5类
    println(p.getClass == classOf[Person5])//false

    //判断p的类型是否为Student5类
    println(p.getClass == classOf[Student5])//true
  }
}

5、访问修饰符

java中的访问控制,同样适用于scala,可以在成员前面添加private/protected关键字来控制成员的可见性。但在scala中,==没有public关键字,任何没有被标为private或protected的成员都是公共的==。
 

==private[this]修饰符==

package com.testScala.F_jicheng
class Person6 {
  // 只有在当前对象中能够访问
  private[this] var name = "super"

  def getName = this.name	// 正确!

  def sayHelloTo(p: Person6) = {
    println("hello" + p.name)     // 报错!无法访问
  }
}

object Person6 {
  def showName(p: Person6) = println(p.name)  // 报错!无法访问
}

protected[this]修饰符==

package com.testScala.F_jicheng

class Person7 {
  // 只有在当前类以及继承该类的当前对象中能够访问
  protected[this] var name = "super"

  def getName = {
    // 正确!
    this.name
  }

  def sayHelloTo1(p: Person7) = {
    // 编译错误!无法访问
//    println(p.name)
  }
}

object Person7 {
  def sayHelloTo3(p: Person7) = {
    // 编译错误!无法访问
//    println(p.name)
  }
}

class Student7 extends Person7 {
  def showName = {
    // 正确!
    println(name)
  }

  def sayHelloTo2(p: Person7) = {
    // 编译错误!无法访问
//    println(p.name)
  }
}
object  yy{
  def main(args: Array[String]): Unit = {
    var yu=    new Student7();
    yu.showName
//    println()
  }
}

6、调用父类的constructor

 ​​​​​​

package com.testScala.F_jicheng

class Person8(var name: String){
  println("name:"+name)
}

// 直接在子类的类名后面调用父类构造器
class Student8(name: String, var clazz: String) extends Person8(name)

object Main8 {
  def main(args: Array[String]): Unit = {
    val s1 = new Student8("张三", "三年二班")
    println(s"${s1.name} - ${s1.clazz}")
  }
}
name:张三
张三 - 三年二班

7、抽象类

package com.testScala.F_jicheng

abstract class Person9(val name: String) {
  //抽象方法
  def sayHello: String
  def sayBye: String
  //抽象字段
  val address: String
}
class Student9(name: String) extends Person9(name){
  //重写抽象方法或字段,def前不必加override关键字
  def sayHello: String = "Hello," + name
  def sayBye: String ="Bye," + name
  //重写抽象字段
   val address: String = "beijing "
}
object Main9{
  def main(args: Array[String]) {
    val s = new Student9("tom")
    println(s.sayHello)
    println(s.sayBye)
    println(s.address)
  }
}
Hello,tom
Bye,tom
beijing 

17、scala面向对象编程之trait特质

1、作为接口使用

==示例一:继承单个trait==  

trait Logger1 {
  // 抽象方法
  def log(msg: String)
}

class ConsoleLogger1 extends Logger1 {
  override def log(msg: String): Unit = println(msg)
}

object LoggerTrait1 {
  def main(args: Array[String]): Unit = {
    val logger = new ConsoleLogger1
    logger.log("控制台日志: 这是一条Log")
  }
}
控制台日志: 这是一条Log

==示例二:继承多个trait==

trait Logger2 {
  // 抽象方法
  def log(msg: String)
}

trait MessageSender {
  def send(msg: String)
}

class ConsoleLogger2 extends Logger2 with MessageSender {

  override def log(msg: String): Unit = println(msg)

  override def send(msg: String): Unit = println(s"发送消息:${msg}")
}

object LoggerTrait2 {
  def main(args: Array[String]): Unit = {
    val logger = new ConsoleLogger2
    logger.log("控制台日志: 这是一条Log")
    logger.send("你好!")
  }
}
控制台日志: 这是一条Log
发送消息:你好!

2、定义具体的方法

package com.testScala.G_trait

trait LoggerDetail {
  // 在trait中定义具体方法
  def log(msg: String) = println(msg)
}

class PersonService extends LoggerDetail {
  def add() = log("添加用户")
}

object MethodInTrait {
  def main(args: Array[String]): Unit = {
    val personService = new PersonService
    personService.add()
  }
}
添加用户

3、定义具体方法和抽象方法

==示例==

package com.testScala.G_trait

trait Logger3 {
  // 抽象方法
  def log(msg: String)
  // 具体方法(该方法依赖于抽象方法log
  def info(msg: String) = log("INFO:" + msg)
  def warn(msg: String) = log("WARN:" + msg)
  def error(msg: String) = log("ERROR:" + msg)
}

class ConsoleLogger3 extends Logger3 {
  override def log(msg: String): Unit = println(msg)
}

object LoggerTrait3 {
  def main(args: Array[String]): Unit = {
    val logger3 = new ConsoleLogger3

    logger3.log("这是一条日志信息")
    logger3.info("这是一条普通信息")
    logger3.warn("这是一条警告信息")
    logger3.error("这是一条错误信息")
  }
}
这是一条日志信息
INFO:这是一条普通信息
WARN:这是一条警告信息
ERROR:这是一条错误信息

4、定义具体字段和抽象字段

package com.testScala.G_trait

import java.text.SimpleDateFormat
import java.util.Date

trait LoggerEx {
  // 具体字段
  val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm")
  val INFO = "信息:" + sdf.format(new Date)
  // 抽象字段
  val TYPE: String

  // 抽象方法
  def log(msg: String)
}

class ConsoleLoggerEx extends LoggerEx {
  // 实现抽象字段
  override val TYPE: String = "控制台"
  // 实现抽象方法
  override def log(msg: String): Unit = print(s"$TYPE$INFO $msg")
}

object FieldInTrait {
  def main(args: Array[String]): Unit = {
    val logger = new ConsoleLoggerEx

    logger.log("这是一条消息")
  }
}
控制台信息:2022-04-24 15:05 这是一条消息

5、实例对象混入trait

package com.testScala.G_trait

trait LoggerMix {
  def log(msg: String) = println(msg)
}

class UserService

object FixedInClass {
  def main(args: Array[String]): Unit = {
    // 使用with关键字直接将特质混入到对象中
    val userService = new UserService with LoggerMix
    userService.log("你好")
  }
}
你好

18、模式匹配和样例类

1、匹配字符串

import scala.util.Random


//todo:匹配字符串
object CaseDemo01 extends App{
  //定义一个数组
  val arr = Array("hadoop", "zookeeper", "spark", "storm")

  //随机取数组中的一位,使用Random.nextInt
  val name = arr(Random.nextInt(arr.length))
  println(name)

  name match {
    case "hadoop"     => println("大数据分布式存储和计算框架...")
    case "zookeeper"  => println("大数据分布式协调服务框架...")
    case "spark"      => println("大数据分布式内存计算框架...")
    //表示以上情况都不满足才会走最后一个
    case _            => println("我不认识你")
  }
}
hadoop
大数据分布式存储和计算框架...

2、匹配类型

//todo:匹配类型
object CaseDemo02 extends App{
  //定义一个数组
  val arr = Array("hello", 1, -2.0, CaseDemo02)

  //随机获取数组中的元素
  val value = arr(Random.nextInt(arr.length))
  println(value)

  value match {
    case x: Int                => println("Int=>"+x)
    case y: Double if(y >= 0)    => println("Double=>"+y)
    case z: String             => println("String=>"+z)
    case _                     => throw new Exception("not match exception")
  }
}
hello
String=>hello

3、匹配数组

package com.testScala.H_pipei

//匹配数组
object CaseDemo03 extends App{

  //匹配数组
  val arr = Array(1, 3, 5)
  arr match {
    case Array(1, x, y) => println(x + "---" + y)
    case Array(1, _*)   => println("1...")
    case Array(0)       => println("only 0")
    case _              => println("something else")

  }
}

1...

4、匹配集合

//匹配集合
object CaseDemo04 extends App{

  val list = List(0, 3, 6)
  list match {
    case 0::Nil        => println("only 0")
    case 0::tail       => println("0....")
    case x::y::z::Nil  => println(s"x:$x y:$y z:$z")
    case _             => println("something else")
  }
}
0....

5、匹配元组

package com.testScala.H_pipei

//匹配元组
object CaseDemo05 extends App{

  val tuple = (1, 3, 5)
  tuple match {
    case (1, x, y)    => println(s"1,$x,$y")
    case (2, x, y)    => println(s"$x,$y")
    case _            => println("others...")
  }
}
1,3,5

6、样例类

case class 样例类名(成员变量名1: 类型1, 成员变量名2: 类型2 ...)

package com.testScala.H_pipei

// 定义一个样例类
// 样例类有两个成员name、age
case class CasePerson(name: String, age: Int)

// 使用var指定成员变量是可变的
case class CaseStudent(var name: String, var age: Int)

object CaseClassDemo {
  def main(args: Array[String]): Unit = {
    // 1. 使用new创建实例
    val zhagnsan = new CasePerson("张三", 20)
    println(zhagnsan)

    // 2. 使用类名直接创建实例
    val lisi = CasePerson("李四", 21)
    println(lisi)

    // 3. 样例类默认的成员变量都是val的,除非手动指定变量为var类型
    //lisi.age = 22  // 编译错误!age默认为val类型

    val xiaohong = CaseStudent("小红", 23)
    xiaohong.age = 24
    println(xiaohong)
  }
}
CasePerson(张三,20)
CasePerson(李四,21)
CaseStudent(小红,24)

样例对象

case object 样例对象名

case class SendMessage(text: String)

// 消息如果没有任何参数,就可以定义为样例对象
case object startTask
case object PauseTask
case object StopTask

case class SubmitTask(id: String, name: String)
case class HeartBeat(time: Long)
case object CheckTimeOutTask

object CaseDemo06 extends App{
  val arr = Array(CheckTimeOutTask,
    HeartBeat(10000),
    SubmitTask("0001", "task-0001"))

  arr(Random.nextInt(arr.length)) match {

    case SubmitTask(id, name) => println(s"id=$id, name=$name")
    case HeartBeat(time)      => println(s"time=$time")
    case CheckTimeOutTask     => println("检查超时")
  }
}
检查超时

7、Option类型

object TestOption {
  def main(args: Array[String]) {
    val map = Map("a" -> 1, "b" -> 2)

    val value: Option[Int] = map.get("b")
    println(value)
    val v1 = value match {
      case Some(i) => i
      case None => 0
    }
    println(v1)

    //更好的方式
    val v2 = map.getOrElse("c", 0)
    println(v2)
  }
}
Some(2)
2
0

8、偏函数

object TestPartialFunction {
  // func1是一个输入参数为Int类型,返回值为String类型的偏函数
  val func1: PartialFunction[Int, String] = {
    case 1 => "一个"
    case 2 => "二个"
    case 3 => "三个"
    case _ => "其他"
  }

  def main(args: Array[String]): Unit = {
    println(func1(1))

    val list = List(1, 2, 3, 4, 5, 6)

    //使用偏函数操作
    val result = list.filter{
      case x if x >3 => true
      case _ => false
    }
    println(result)
  }

19、异常处理

 ​​​​​​

def main(args: Array[String]): Unit = {
   val i = 10 / 0
    
    println("你好!")
  }

Exception in thread "main" java.lang.ArithmeticException: / by zero
	at ForDemo$.main(ForDemo.scala:3)
	at ForDemo.main(ForDemo.scala)

执行程序,可以看到scala抛出了异常,而且没有打印出来"你好"。说明程序出现错误后就终止了。那怎么解决该问题呢?

1、 捕获异常

try {
    // 代码
}
catch {
    case ex: 异常类型1 => // 代码
    case ex: 异常类型2 => // 代码
}
finally {
    // 代码

try {
    val i = 10 / 0

} catch {
    case ex: Exception => println(ex.getMessage)
} finally {
    println("我始终都会执行!")
}

2、抛出异常

  def main(args: Array[String]): Unit = {
    throw new Exception("这是一个异常")
  }

Exception in thread "main" java.lang.Exception: 这是一个异常
	at ForDemo$.main(ForDemo.scala:3)
	at ForDemo.main(ForDemo.scala)

20、提取器(Extractor)

package com.testScala.I_Extractor

class Student {
  var name: String = _   // 姓名
  var age: Int = _       // 年龄

  // 实现一个辅助构造器
  def this(name: String, age: Int) = {
    this()

    this.name = name
    this.age = age
  }
}

object Student {
  def apply(name: String, age: Int): Student = new Student(name, age)

  // 实现一个解构器
  def unapply(arg: Student): Option[(String, Int)] = Some(arg.name, arg.age)
}

object extractor_DEMO {
  def main(args: Array[String]): Unit = {
    val zhangsan = Student("张三", 20)

    zhangsan match {
      case Student(name, age) => println(s"姓名:$name 年龄:$age")
      case _ => println("未匹配")
    }
  }
}
姓名:张三 年龄:20

21、泛型

    scala和Java一样,类和特质、方法都可以支持泛型。我们在学习集合的时候,一般都会涉及到泛型。

在scala中,使用方括号来定义==类型参数==。

1、定义一个泛型方法

object learn01 {
  def getMiddle[A](arr: Array[A]) = arr(arr.length / 2)

  def main(args: Array[String]): Unit = {
    val arr1 = Array(1, 2, 3, 4, 5)
    val arr2 = Array("a", "b", "c", "d", "f")

    println(getMiddle[Int](arr1))
    println(getMiddle[String](arr2))

    // 简写方式,scala自动进行类型推断
    println(getMiddle(arr1))
    println(getMiddle(arr2))
  }
}

2、定义一个泛型类

定义一个Pair类包含2个类型不固定的泛型

package com.testScala.J_fanxing


  // 类名后面的方括号,就表示这个类可以使用两个类型、分别是T和S
  // 这个名字可以任意取
  class Pair[T, S](val first: T, val second: S)

  case class People(var name: String, val age: Int)

  object Pair {
    def main(args: Array[String]): Unit = {

      val p1 = new Pair[String, Int]("张三", 10)
      println(p1.first)
      val p2 = new Pair[String, String]("张三", "1988-02-19")
      println(p2.first)
      val p3 = new Pair[People, People](People("张三", 20), People("李四", 30))
      println(p3.first.age)
    }
  }
张三
张三
20

22、上下界

package com.testScala.J_fanxing

// 类名后面的指定泛型的范围 ----上界
class Pair1[T <: Person, S <: Person](val first: T, val second: S) {
  def chat(msg: String) = println(s"${first.name}对${second.name}说: $msg")
}

class Person(var name: String, val age: Int)

object Pair1 {
  def main(args: Array[String]): Unit = {

    val p3 = new Pair1[Person, Person](new Person("张三", 20), new Person("李四", 30))
    p3.chat("你好啊!")
  }
}
张三对李四说: 你好啊!

==示例二==

class Pair22[T <: Person, S >: Policeman <: Person](val first: T, val second: S) {
  def chat(msg: String) = println(s"${first.name}对${second.name}说: $msg")
}

class Person(var name: String, val age: Int)
class Policeman(name: String, age: Int) extends Person(name, age)
class Superman(name: String) extends Policeman(name, -1)

object Pai {
  def main(args: Array[String]): Unit = {
    // 编译错误:第二个类型参数必须是Person的子类(包括本身)、Policeman的父类(包括本身)
    val p3 = new Pair22[Person, Policeman](new Person("张三", 20), new Policeman("李四",20))
    p3.chat("你好啊!")
  }
}
张三对李四说: 你好啊!

23、协变、逆变、非变

class Pair[T](a: T)

object Pair {
  def main(args: Array[String]): Unit = {
    val p1 = new Pair("hello")
    // 编译报错,无法将p1转换为p2
    val p2: Pair[AnyRef] = p1

    println(p2)
  }
}

==协变==

class Pair[+T],这种情况是协变。类型B是A的子类型,Pair[B]可以认为是Pair[A]的子类型。这种情况,参数化类型的方向和类型的方向是一致的。

==逆变==

class Pair[-T],这种情况是逆变。类型B是A的子类型,Pair[A]反过来可以认为是Pair[B]的子类型。这种情况,参数化类型的方向和类型的方向是相反的。 

==非变==

class Pair[T]{},这种情况就是非变(默认),类型B是A的子类型,Pair[A]和Pair[B]没有任何从属关系,这种情况和Java是一样的。 

package com.testScala.K_xieBian

class Super
class Sub extends Super

//非变
class Temp1[A](title: String)
//协变
class Temp2[+A](title: String)
//逆变
class Temp3[-A](title: String)

object Covariance_demo {
  def main(args: Array[String]): Unit = {
    val a = new Sub()
    // 没有问题,Sub是Super的子类
    val b: Super = a

    // 非变
    val t1: Temp1[Sub] = new Temp1[Sub]("测试")
    // 报错!默认不允许转换
    // val t2: Temp1[Super] = t1

    // 协变
    val t3: Temp2[Sub] = new Temp2[Sub]("测试")
    val t4: Temp2[Super] = t3

    // 逆变
    val t5: Temp3[Super] = new Temp3[Super]("测试")
    val t6: Temp3[Sub] = t5
  }
}

 ==总结==

C[+T]:如果A是B的子类,那么C[A]是C[B]的子类。
C[-T]:如果A是B的子类,那么C[B]是C[A]的子类。
C[T]: 无论A和B是什么关系,C[A]和C[B]没有从属关系。

24、隐式转换和隐式参数

1 隐式转换

.2 隐式参数

到此这篇关于Scala基础语法总结的文章就介绍到这了,更多相关Scala基础语法详解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文