scala学习第一篇之基础语法

一、scala基础语法

1、Hello Scala

类似于java上来的第一个程序肯定离不开“Hollo World”,这里呢,第一个scala程序也是打印输出"hello world"

?:
object HelloWorld {
// 作用类似于 Java 的 main 方法
def main(args: Array[String]): Unit = {
println("hello world") }
}

关于HelloWorld程序:我们比较一下Scala 和 Java 不同处:

  • 1、文件后缀名(.java和.scala)
  • 2、编译和运行方式 (java编译是java classpath,运行是javac classpath;scala编译文件是scala classpath,运行是scalac classpath)
  • 3、类的声明 (java使用public static void main;scala使用def main)
  • 4、main 方法的声明
  • 5、分号,scala可以不用以分号表示语句的结束

2、变量定义

在scala中数据类型可以指定,也可以不指定,如果不指定,那么就会进行数据类型的自动推断(甚是强大);
如果指定数据类型,数据类型的执行方式是在变量名后面写一个冒号,然后写上数据类型。
scala里面变量的修饰符一共有两个,一个是 var,一个是 val
如果是 var 修饰的变量,那么这个变量的值是可以修改的,虽然可以修改,但是不能改成其他类型的值,如果是 val修饰的变量,那么这个变量的值是不可以修改的

?:
object VariableDemo {
def main(args: Array[String]) {
//使用 val 定义的变量值是不可变的,相当于 java 里用 final 修饰的变量 val i = 1
//使用 var 定义的变量是可变得,在 Scala 中鼓励使用 val
var s = "hello"
//Scala 编译器会自动推断变量的类型,必要的时候可以指定类型 //变量名在前,类型在后
val str: String = "spark"
} }

3、数据类型

3.1数据类型概述

Scala 和 Java 一样,有 7 种数值类型 Byte、Char、Short、Int、Long、Float 和 Double(无包 装类型)和一个 Boolean 类型,再加上常用的 String 类型
注意:scala 里面没有基本数据类型和包装类型之说。
在这里插入图片描述
下图是scala数据类型关系图:
在这里插入图片描述
总结下来一共有七个要点:

  • 1、 Any 是所有类的父类,包括值类型 AnyVal,和引用类型 AnyRef
    
  • 2、 AnyVal 是所有值类型的父类,包括 Int,Double,Boolean,Unit 等等
    
  • 3、 AnyRef 是所有引用类型的父类,包括 Null
    
  • 4、 Null 是所有引用类型的子类
    
  • 5、 Nothing 是所有类的子类
    
  • 6、 Unit 类型只有一个实例,是(),相当于 java 中的 void,没有任何的实质意义
    
  • 7、 Null 也只有一个实例,是 null,相当于 java 中的 null,能赋值给任何引用类型变量,不能赋值给值类型变量
    

3.2Scala 基本类型操作

跟java基本一样,就不一一赘述了

算术操作:+ - * / %
关系运算:> >= < <= == !=
逻辑运算:&& || !
位运算:& | ^ ~ >> << >>>
对象比较:ne eq equals ==

4、流程控制–条件表达式 if

①if 条件表达式它是有返回值的,返回值是多个分支的返回结果的共同父类
②返回值会根据条件表达式的情况会进行自动的数据类型的推断(返回的是多个分支的共同父类)

?:
object ConditionDemo {
def main(args: Array[String]) {
val x = 1
//判断 x 的值,将结果赋给 y
val y = if (x > 0) 1 else -1 //打印 y 的值
println(y)
//支持混合类型表达式
val z = if (x > 1) 1 else "error" //打印 z 的值
println(z)
//如果缺失 else,相当于 if (x > 2) 1 else () val m = if (x > 2) 1
println(m)
//在 scala 中每个表达式都有值,scala 中有个 Unit 类,写做(),相当于 Java 中的 void 
val n = if (x > 2) 1 else ()
println(n)
//if 和 else if
val k = if (x < 0) 0
else if (x >= 1) 1 else -1 println(k)
} }

5、块表达式

在 scala 中{}中可以包含一系列表达式,块中最后一个表达式的值就是块的值

?:
object BlockExpresstionDemo { def main(args: Array[String]) {
val x = 0
//下面就是一个块表达式
val result = {
if (x < 0){ 
-1
} else if(x >= 1) { 
1
} else { 
"error"
}
//这个地方如果写上2,那么最终result值就是2
//2
}
//result 的值就是块表达式的结果
println(result) }
}

注意: 就算是赋值表达式,也是有返回值的。是空,是 Unit

6、流程控制–循环 for 和 while

6.1for循环

for 循环语法结构:for (i <- 表达式/数组/集合)

1、在 scala 里面没有运算符,所有的符号其实都是方法;
2、在 scala 里面没有 ++ – 的用法;
3、for( i <-表达式/数组/集合);
4、在 for 循环里面我们是可以添加 if 表达式;
5、有两个特殊表达式需要了解:
在这里插入图片描述
6、如果在使用 for 循环的时候,for循环的时候我们需要获取,我们可以是使用yield关键字

?:
object ForDemo {
  def main(args: Array[String]) {
    //for(i <- 表达式),表达式 1 to 10 返回一个 Range(区间) 
    //每次循环将区间中的一个值赋给 i
    for (i <- 1 to 10)
      println(i)
    //for(i <- 数组)
    val arr = Array("a", "b", "c") for (i <- arr)
      println(i)
    // 倒序打印
    for (str <- arr.reverse) {
      println(str)
    }
    // 使用数组下标的方式进行打印
    for (i <- 0 to arr.length - 1) {
      println(arr(i))
    }
    for (i <- 0 until arr.length)
      println(arr(i))
    println("-----------------")
    for (i <- 0 until(arr.length, 2))
      println(arr(i))
    //高级 for 循环
    //每个生成器都可以带一个条件,注意:if 前面没有分号 
    for (i <- 1 to 3; j <- 1 to 3 if i == j)
      println((10 * i + j) + " ")
    println()
    //for 推导式:如果 for 循环的循环体以 yield 开始,则该循环会构建出一个集合 
    //每次迭代生成集合中的一个值
    val v = for (i <- 1 to 10) yield i * 10
    println(v)
  }
}

6.2while循环

while使用跟 java中一模一样
注意点: 在 scala 里面不支持 i++ i-- 等操作统一写成 i+=1 i-=1

?:
object WhileDemo {
	def main(args: Array[String]) {
		var n = 10
		while (n > 0) {
			println(n)
			n -= 1 
		}
	}
}

7、方法和函数

Scala 中的+ - * / %等操作符的作用与 Java 一样,位操作符 & | ^ >> <<也一样。 只是有一点特别的:这些操作符实际上是方法。例如:
a+b
是如下方法调用的简写:
a.+(b)
a 方法 b 可以写成 a.方法(b)

7.1方法

方法的返回值类型可以不写,编译器可以自动推断出来,但是对于递归函数,必须指定返回类型
在这里插入图片描述

7.2函数

函数的意义:表示接受两个 Int 类型的变量,然后做累加。
经过 scala 的自动类型推断得知,最后返回的结果数据的类型也是 Int。
在这里插入图片描述

7.3方法和函数的区别

Scala 方法与函数二者区别不是很大。Scala方法是类的一部分,而函数是一个对象可以赋值给一个变量。换句话说那就是在类中定义的函数就是方法。

Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了 Trait (特质,类似于java的接口)的类的对象。

Scala 中使用 val 语句可以定义函数,def 语句定义方法。

7.3.1函数可以作为参数传递给方法,也就是说函数可以作为方法的参数

在函数式编程语言中,函数是“头等公民”,它可以像任何其他数据类型一样被传递和操作

?:
object MethodFunction{
  //方法 m1 参数要求是一个函数,函数的参数必须是两个Int类型
  def m1(f:(Int,Int) => Int) : Int = {
    f(2,6)
  }

  //定义一个函数f1,参数是两个Int类型,返回值是一个Int类型
  val f1 = (x:Int,y:Int) => x + y
  //再定义一个函数f2
  val f2 = (m:Int,n:Int) => m * n

  //main方法
  def main(args: Array[String]): Unit = {
    //调用m1方法,并传入f1函数
    val r1 = m1(f1)
    println(r1)
    //调用m1方法,并传入f2函数
    val r2 = m1(f2)
    println(r2)
  }
}
7.3.2函数可以作为方法的参数,但是也可以作为函数的参数
7.3.3方法也可以作为方法的参数。在需要传入函数作为参数的位置上传入一个方法的话,那么这个方法会被自动的转换为函数作为参数,也可以通过“_”把方法转换为参数
7.3.4方法也可以作为函数的参数。其实,原理就是方法会被自动转换为函数,所以也就是传入一个函数到一个函数作为参数。

我总结的不是很好,这里推荐一篇博客:
https://blog.csdn.net/qq_29343201/article/details/56282779

8、Scala 数组 Array

8.1定长数组和变长数组

1、由于 Array 是不可变(长度不可变)的,初始化之初就有了固定的长度,所以不能直接地对其元素进行删除操作,也不能多增加元素,只能修改某个位置的元素的值,要实现删除可以通过过滤生成新的 Array 的方式来删除不要的元素。所以也就没有 add,insert,remove等操作。
2、而 ArrayBuffer 是可变的,本身提供了很多元素的操作,当然包括增加,删除操作。
3、如果你需要在 Array 和ArrayBuffer 之间转换,那么分别调用 toBuffer()和 toArray()方法即可

?:
object ArrayDemo {
  def main(args: Array[String]) {
    //初始化一个长度为 8 的定长数组,其所有元素均为 0 
    val arr1 = new Array[Int](8) 
    //直接打印定长数组,内容为数组的 hashcode 值 println(arr1) 		
    //将数组转换成数组缓冲,就可以看到原数组中的内容了
    //toBuffer 会将数组转换长数组缓冲 println(arr1.toBuffer)
    //注意:如果 new,相当于调用了数组的 apply 方法,直接为数组赋值 
    //初始化一个长度为 1 的定长数组
    val arr2 = Array[Int](10)
    println(arr2.toBuffer)

    //定义一个长度为 3 的定长数组
    val arr3 = Array("hadoop", "storm", "spark") //使用()来访问元素
    println(arr3(2))
   
    //变长数组(数组缓冲)
    //如果想使用数组缓冲,需要导入 import scala.collection.mutable.ArrayBuffer 包 val ab = ArrayBuffer[Int]()
    //向数组缓冲的尾部追加一个元素 //+=尾部追加元素
    ab += 1
    //追加多个元素
    ab +=(2, 3, 4, 5) //追加一个数组++= ab ++= Array(6, 7)
    //追加一个数组缓冲
    ab ++= ArrayBuffer(8, 9) //打印数组缓冲 ab
    //在数组 个位置插入元素用 insert ab.insert(0, -1, 0) 
    //删除数组 个位置的元素用 remove
    ab.remove(8, 2) println (ab)
  }
}

8.2遍历数组

三种方法:

增强 for 循环
使用 to 可以生成序列,0 to 10 包含 0 包含 10
使用好用的 until 会生成脚标,0 until 10 包含 0 不包含 10

?:
object ArrayForDemo {
  def main(args: Array[String]) { 
  //初始化一个数组
  val arr = Array(1,2,3,4,5,6,7,8)
    //增强 for 循环 for(i <- arr) println(i)
    //使用 to 可以生成一个序列作为脚标
    for(i <- (0 to arr.length - 1).reverse)
      println(arr(i))
    //好用的 until 会生成一个 Range,reverse 是将前面生成的 Range 反转 for(i <- (0 until arr.length).reverse)
    println(arr(i)) //步长为 2
    for(i <- (0 until (arr.length, 2)).reverse) println(arr(i))
  }
}

8.3数组转换(yield关键字)

yield 关键字将原始的数组进行转换会产生一个新的数组,原始的数组不变

?:
object ArrayYield {
  def main(args: Array[String]) {
    //定义一个数组
    val arr = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
    //将偶数取出乘以 10 后再生成一个新的数组
    val res = for (e <- arr if e % 2 == 0) yield e * 10 println(res.toBuffer)
    //更高级的写法,用着更爽
    //filter 是过滤,接收一个返回值为 boolean 的函数
    //map 相当于将数组中的每一个元素取出来,应用传进去的函数 val r = arr.filter(_ % 2 == 0).map(_ * 10) println(r.toBuffer)
  }
}

8.4数组常用的方法

使用数组名.然后按住tab键就能出出来数组的所有方法
在这里插入图片描述

8.5多维数组

在这里插入图片描述

9、Scala 集合

Scala 的集合有三大类:序列 Seq、集合 Set、映射 Map,所有的集合都扩展自 Iterable 特质,在 Scala 中集合有可变(mutable)和不可变(immutable)两种类型,immutable 类型的集合初始化后就不能改变了(注意与 val 修饰的变量进行区别)
两个补充概念:

val 和 var:表明定义的变量(引用)是否能被修改而指向其他内容

immutable 和 mutable:表明的是内存中开辟出来的这块空间里的内容能否被修改,如果针对 immutable变量进行修改,其实是开辟了一块新的内存空间,产生了一个新的变量,而 原来的变量依然没有改变

9.1scala集合之序列List

在 Scala 中列表要么为空(Nil 表示空列表)要么是一个 head 元素加上一个 tail 列表。
9 :: List(5, 2) :: 操作符是将给定的头和尾创建一个新的列表
注意::: 操作符是右结合的,如9 :: 5 :: 2 :: Nil相当于 9 :: (5 :: (2 :: Nil))

9.1.1不可变list

?:
object ImmutableListDemo {
def main(args: Array[String]) { 
//创建一个不可变的集合
val lst1 = List(1,2,3)
//将 0 插入到 lst1 的前面生成一个新的 List val lst2 = 0 :: lst1
val lst3 = lst1.::(0)
val lst4 = 0 +: lst1
val lst5 = lst1.+:(0)
//将一个元素添加到 lst1 的后面产生一个新的集合 val lst6 = lst1 :+ 3
val lst0 = List(4,5,6)
//将 2 个 list 合并成一个新的 List
val lst7 = lst1 ++ lst0
//将 lst0 插入到 lst1 前面生成一个新的集合 val lst8 = lst1 ++: lst0
//将 lst0 插入到 lst1 前面生成一个新的集合 val lst9 = lst1.:::(lst0)
println(lst9)
} }

在这里插入图片描述
序列常用操作:

?:
//采用::及 Nil 进行列表构建
scala> val nums = 1 :: (2 :: (3 :: (4 :: Nil))) nums: List[Int] = List(1, 2, 3, 4)
//由于::操作符的优先级是从右往左的,因此上一条语句等同于下面这条语句 scala> val nums=1::2::3::4::Nil
nums: List[Int] = List(1, 2, 3, 4)
//判断是否为空 
scala> nums.isEmpty res108: Boolean = false
//取第一个无素 
scala> nums.head res109: Int = 1
//取除第一个元素外剩余的元素,返回的是列表 scala> nums.tail
res114: List[Int] = List(2, 3, 4)
//取列表第二个元素 
scala> nums.tail.head res115: Int = 2
//List 连接操作
scala> List(1,2,3):::List(4,5,6) 
res116: List[Int] = List(1, 2, 3, 4, 5, 6)
//取除最后一个元素外的元素,返回的是列表 scala> nums.init
res117: List[Int] = List(1, 2, 3)
//取列表最后一个元素 
scala> nums.last res118: Int = 4
//列表元素倒置
scala> nums.reverse
res119: List[Int] = List(4, 3, 2, 1)

scala> nums.reverse.reverse==nums 
res120: Boolean = true
scala> nums.reverse.init 
res121: List[Int] = List(4, 3, 2)
scala> nums.tail.reverse 
res122: List[Int] = List(4, 3, 2)
//丢弃前 n 个元素 
scala> nums drop 3 
res123: List[Int] = List(4)
scala> nums drop 1
res124: List[Int] = List(2, 3, 4)
//获取前 n 个元素 
scala> nums take 1 
res125: List[Int] = List(1)
scala> nums.take(3)
res126: List[Int] = List(1, 2, 3)
//将列表进行分割
scala> nums.splitAt(2)
res127: (List[Int], List[Int]) = (List(1, 2),List(3, 4))
//前一个操作与下列语句等同
scala> (nums.take(2),nums.drop(2))
res128: (List[Int], List[Int]) = (List(1, 2),List(3, 4))


//Zip 操作
scala> val nums=List(1,2,3,4) 
nums: List[Int] = List(1, 2, 3, 4)
scala> val chars=List('1','2','3','4') 
chars: List[Char] = List(1, 2, 3, 4)
//返回的是 List 类型的元组(Tuple)
scala> nums zip chars
res130: List[(Int, Char)] = List((1,1), (2,2), (3,3), (4,4))
//List toString 方法
scala> nums.toString
res131: String = List(1, 2, 3, 4)
//List mkString 方法 
scala> nums.mkString 
res132: String = 1234
//转换成数组
scala> nums.toArray
res134: Array[Int] = Array(1, 2, 3, 4)

9.1.1可变list

?:
import scala.collection.mutable._

object MutableListDemo extends App{ 
//构建一个可变列表,初始有 3 个元素 1,2,3 
val lst0 = ListBuffer[Int](1,2,3) 
//创建一个空的可变列表
val lst1 = new ListBuffer[Int]
//向 lst1 中追加元素,注意:没有生成新的集合 lst1 += 4
lst1.append(5)
//将 lst1 中的元素最近到 lst0 中, 注意:没有生成新的集合 lst0 ++= lst1
//将 lst0 和 lst1 合并成一个新的 ListBuffer 注意:生成了一个集合 val lst2= lst0 ++ lst1
//将元素追加到 lst0 的后面生成一个新的集合
val lst3 = lst0 :+ 5 
}

9.2scala集合之Set

9.2.1不可变set
?:
import scala.collection.immutable.HashSet
object ImmutableSetDemo extends App{//继承了APP后就不用定义main方法也能运行
val set1 = new HashSet[Int]()
//将元素和 set1 合并生成一个新的 set,原有 set 不变 val set2 = set1 + 4
//set 中元素不能重复
val set3 = set1 ++ Set(5, 6, 7)
val set0 = Set(1,3,4) ++ set1 
println(set0.getClass)
}
9.2.1可变set
?:
import scala.collection.mutable
object MutableSetDemo extends App{ 
//创建一个可变的 HashSet
val set1 = new mutable.HashSet[Int]() 
//向 HashSet 中添加元素
set1 += 2
//add 等价于+=
set1.add(4)
set1 ++= Set(1,3,5) 
println(set1) 
//删除一个元素
set1 -= 5 
set1.remove(2) 
println(set1)
}

9.3scala集合之Map

在 Scala 中,把哈希表这种数据结构叫做映射,在 Java 中也叫做映射
注意:

在 Scala 中,有两种 Map,一个是 immutable 包下的 Map,该 Map 中的内容不可变; 另一个是 mutable包下的 Map,该 Map 中的内容可变

带值的map的创建:
在这里插入图片描述

?:
import scala.collection.mutable

object MutableMapDemo extends App{
val map1 = new mutable.HashMap[String, Int]() 
//向 map 中添加数据
map1("spark") = 1
map1 += (("hadoop", 2))
map1.put("storm", 3)
println(map1)
//从 map 中移除元素 
map1 -= "spark" 
map1.remove("hadoop") 
println(map1)
}

Map常用方法:

?:
scala> val studentInfo=Map("john" -> 21, "stephen" -> 22,"lucy" -> 20)
studentInfo: scala.collection.immutable.Map[String,Int] = Map(john -> 21, stephen -> 22, lucy -> 20)
scala> studentInfo.clear()
<console>:13: error: value clear is not a member of scala.collection.immutable.Map[String,Int]
studentInfo.clear() 
					^
scala> val studentInfoMutable=scala.collection.mutable.Map("john" -> 21, "stephen" -> 22,"lucy" -> 20) 
studentInfoMutable: scala.collection.mutable.Map[String,Int] = Map(john -> 21, lucy -> 20, stephen -> 22)
scala> studentInfoMutable.clear()
scala> studentInfoMutable
res2: scala.collection.mutable.Map[String,Int] = Map()
scala> for( i <- studentInfoMutable ) println(i)
scala> val studentInfoMutable=scala.collection.mutable.Map("john" -> 21, "stephen" -> 22,"lucy" -> 20) 
studentInfoMutable: scala.collection.mutable.Map[String,Int] = Map(john -> 21, lucy -> 20, stephen -> 22)
scala> for( i <- studentInfoMutable ) println(i) (john,21)
(lucy,20)
(stephen,22)
scala> studentInfoMutable.foreach(e=> println(e._1+":"+e._2)) john:21
lucy:20
stephen:22
scala> val xMap=new scala.collection.mutable.HashMap[String,Int]() 
xMap: scala.collection.mutable.HashMap[String,Int] = Map()
scala> xMap.put("spark",1)
res6: Option[Int] = None
scala> xMap.put("spark",1) 
res7: Option[Int] = Some(1)
scala> xMap.contains("spark") 
res8: Boolean = true
scala> val xMap=scala.collection.mutable.Map(("spark",1),("hive",1)) 
xMap: scala.collection.mutable.Map[String,Int] = Map(spark -> 1, hive -> 1)
scala> "spark" -> 1
res9: (String, Int) = (spark,1)
scala> xMap.get("spark") 
res10: Option[Int] = Some(1)
scala> xMap.get("SparkSQL") 
res11: Option[Int] = None

补充:
Option, None, Some 类型

Option、None、Some 是 scala 中定义的类型,它们在 scala 语言中十分常用,因此这三个类 型非学重要。 None、Some 是 Option 的子类,它主要解决值为 null 的问题,在 java 语言中, 对于定义好的 HashMap,如果 get 方法中传入的键不存在,方法会返回 null,在编写代码的 时候对于 null 的这种情况通常需要特殊处理,然而在实际中经常会忘记,因此它很容易引起 NullPointerException 异常。在 Scala 语言中通过 Option、None、Some 这三个类来避免这样 的问题,这样做有几个好处,首先是代码可读性更强,当看到 Option 时,我们自然而然就 知道它的值是可选的,然后变量是 Option,比如 Option[String]的时候,直接使用 String 的话, 编译直接通不过。

9.4Scala 元组(Tuple)

与列表一样,元组也是不可变的,但与列表不同的是元组可以包含不同类型的元素。元组的值是通过将单个的值包含在圆括号中构成的。
映射是 K/V 对偶的集合,对偶是元组的最简单形式,元组可以装着多个不同类型的值。

9.4.1元组的创建

在这里插入图片描述

9.4.2元组数值获取

在这里插入图片描述

9.4.3将对偶的元组转成String

在这里插入图片描述
这里提一下,那就是Array可以通过toMap方法变为Map集合
在这里插入图片描述

9.4.4元组拉链操作

使用zip 命令可以将多个值绑定在一起
在这里插入图片描述
注意: 如果两个数组的元素个数不一致,拉链操作后生成的数组的长度为较小的那个数组的 元素个数
相反操作操作是:unzip

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值