if 表达式

Scala中 if 表达式有返回值。

如果if 和 else 的返回值类型不一样,那么就返回两个返回值类型公共的父类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
object IfDemo {
def main(args: Array[String]): Unit = {
//在Scala中不需要添加分号作为语句块的结束符
val num = 20

//在Scala中 if else语句是有返回值的,返回值就是最后一条语句的返回值
if (num > 20) "zhangsan" else "jacky"

//if语句可以嵌套
if (num < 20)
0
else if (num == 20)
1
else
-1

//因为if else语句是有返回值的,所以可以直接将if else语句赋值给一个变量
//注意:返回值不需加return关键字
val result = if (num > 20) "zhangsan" else "jacky"

//如果if else语句中返回值的类型不一样,那么Scala会自动推断出两者的公共父类型,作为表达式的返回值类开型
val result2: Any = if (num == 20) "jacky" else 100
println(result2)

//如果if else语句中缺省了else语句块,那么默认else的值是Unit
//Unit用“()”来表示,类似于Java中的void
val result3 = if (num > 20) "jacky"
val result4 = if (num > 20) "jacky" else ()
}
}

for 表达式

Scala中,for循环语法结构:for (i <- 表达式 / 集合),让变量 i 遍历<-右边的表达式/集合的所有值。

Scala为for循环提供了很多的特性,这些特性被称之为 for守卫式 或 for推导式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
object ForDemo {
def main(args: Array[String]): Unit = {
//for基本结构,使用to实现左右两边闭合的访问区间[1,10]
for (i <- 1 to 10) {
println(s"i = $i")
}

//for基本结构,使用until实现左闭右开的访问区间[1,10)
for (i <- 1 until (10)) {
println(s"i = $i")
}

//双重循环,相当于Java中的嵌套循环,条件之间用分号分隔
println("=============双重循环=================")
for (i <- 1 to 3; j <- 1 to 5) {
println(i * j)
}

println("=============循环中使用变量=================")
for (i <- 1 to 3; j = 4 - i) {
println(i * j)
}

println("=============守卫式,增加了if条件语句=================")
//注意:if前面没有分号
for (i <- 1 to 10; j <- 1 to 10 if i == j) {
println(s"i * j = $i * $j =${i * j}")
}

println("=============推导式,使用yield接收返回结果=================")
//如果for循环的循环体以yield开始,那么此循环会构造出一个集合,每次迭代生成集合中的一个值。
//可以使用变量接收产生的新集合
val result = for (i <- 1 to 5) yield i % 2
result.foreach(println(_))

println("=============九九乘法表=================")
for (i <- 1 to 9; j <- 1 to i) {
print(s"$j * $i = ${i * j}\t")
if (i == j) println()
}

println("=============for循环中使用大括号=================")
for {
i <- 1 to 3
from = 4 - i
j <- from to 3
}
println(s"i=$i,j=$j")

println("=============遍历字符串=================")
val message="sparkscala"
for(elem <- message) print(elem+" ")
}
}

while 表达式

Scala提供了与 Java 类似的while和do…while循环。while语句的本身没有任何返回值类型,即while语句的返回结果是Unit类型的 () 。

Scala内置控制结构特地去掉了 break 和 continue。

特殊情况下如果需要终止循环,可以有以下三种方式:

  • 使用Boolean类型的控制变量

  • 使用return关键字

  • 使用breakable和break,需要导入scala.util.control.Breaks包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
object WhileDemo {
def main(args: Array[String]): Unit = {
var num = 1
// while (num < 10) {
// println(s"num = $num")
// num += 1
// }
// do {
// println(s"num = $num")
// num += 1
// } while (num < 10)

//使用Boolean类型的控制变量,终止循环
// var flag = true
// while (flag) {
// println(s"num = $num")
// num += 1
// if(num==5) flag=false
// }

//使用return关键字终止循环
// for (i <- 1 to 10) {
// if (i == 5) return
// println(s"i=$i")
// }

//使用breakable和break终止循环,需要导入scala.util.control.Breaks包
import scala.util.control.Breaks._
var res = 0
breakable {
for (i <- 1 until (10)) {
if (i == 5) break()
res += i
}
}
println(res)
}
}

函数


函数体中最后一句为返回值的话,可以将return 去掉;如果一个函数体只有一句代码,大括号可以去掉;

如果一个函数没有返回值,其返回类型为Unit , 并且 “=” 号可以去掉,这样的函数被称为过程;

可以不声明函数的返回类型,返回类型可通过自动类型推断来完成,但递归函数的返回类型必须声明;

备注:建议明确声明函数的返回值,即使为Unit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
object FunctionDemo {
/**
* 定义函数的语法结构:def 函数名(参数列表):返回值类型={函数体}
* 函数体中最后一条语句的返回值作为整个函数的返回值,返回值不需要使用return关键字
* 也可以不声明函数的返回值类型,Scala会自动根据最后一条语句的返回值推断出函数的返回值类型
* 但是,如果是递归函数,其返回值类型必须声明
*
* @param num1
* @param num2
* @return
*/
def add(num1: Int, num2: Int) = {
num1 + num2
}

// 通过递归的函数来计算阶乘
def factorial(num: Int): Long = {
if (num <= 1)
1
else
num * factorial(num - 1)
}

// 通过递归函数实现一个斐波那契数列:1,1,2,3,5,8.....
def fibonacci(n: Int): Long = {
if (n == 1 || n == 2) {
1
} else {
fibonacci(n - 1) + fibonacci(n - 2)
}
}

//如果函数没有返回值,其返回值类型为Unit,类似于Java中的void,“=”也可以省略
//在Scala中,没有返回值的函数称为过程
def getSum(x: Int, y: Int) {
println(x + y)
}

//函数中的参数可以有默认值,称为默认参数
def add2(x: Int = 10, y: Int = 20): Unit = {
x + y
}

//变长参数:参数类型右边加上*号
//变长参数只能出现在参数列表的尾部,并且只能有一个
//在Spark的源码中有大量的变长参数
def addSum(nums: Int*): Int = {
nums.sum
}


def main(args: Array[String]): Unit = {
println(add(1, 2))
println("计算阶乘:" + factorial(4))
println("斐波那契数列:" + fibonacci(6))
//调用函数时,使用函数中的参数的默认值
println(add2())
//调用函数时,给函数的参数重新赋值
println(add2(30, 40))
//在调用函数时,不按照函数定义的参数顺序来传递值,而是使用带名参数的方式来传值
println(add2(y = 60, x = 50))
println(addSum(1))
println(addSum(1, 2, 3))
println(addSum(1, 2, 3, 4, 5))
//使用 parameter:_*的形式,告诉编译器这个参数被当成参数序列处理
println(addSum(1 to 10: _*))
}
}

懒值

val被声明为lazy时(var不能声明为lazy),它的初始化将被推迟,直到首次对此取值,适用于初始化开销较大的场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 在Scala中提供了lazy的特性
* 如果将一个变量声明为lazy,那么只有第一次使用这个变量时,变量对应的表达式才会发生计算。
* 这种特性对于特别耗时的计算操作特别有用,
* 比如:初始化开销较大的场景,对文件进行IO、进行网络IO的操作等
*/
object LazyDemo {
def main(args: Array[String]): Unit = {
//使用lazy关键字之后,即使文件不存在,也不会报错
//只有第一次使用变量时才会报错
lazy val file1=scala.io.Source.fromFile("src/test.scala")
println("OK!")
file1.getLines().size
}
}

文件操作

导入scala.io.Source后,可引用Source中的方法读取文本文件的内容

import java.io.PrintWriter

import scala.io.{BufferedSource, Source}

/**
 * I/O操作是一门编程语言的重要内容
 * 相比于Java语言中的I/O类,Scala中的I/O的类数量较少,最常用的是Source这个类。
 * 在Scala中,更多的是调用Java中的 I/O类或者通过对Java中的I/O类进行相应的封装来实现I/O操作。
 */
object FileDemo {
  //读取文本文件
  def readTextFile: Unit = {
    val file = Source.fromFile("src\\text.txt")
    val lines: Iterator[String] = file.getLines()

    for (line <- lines) {
      println(line)
    }
    //关闭文件
    file.close()
  }

  //读取网络资源,需要在联网状态下
  def readNetSource: Unit = {
    val source: BufferedSource = Source.fromURL("http://www.baidu.com")
    val message: String = source.mkString

    println(message)

    source.close()
  }

  //写入文本文件
  //Scala中没有内建的对写入文件的支持,需要使用java.io.PrintWriter来实现
  def writeTextFile: Unit = {
    val writer = new PrintWriter("src\\text.txt")
    for (i <- 1 to 10) {
      //写入文件内容
      writer.println(s"i = $i")
      //刷新printwriter流的缓冲区
      writer.flush()
    }

    //关闭写入流
    writer.close()
  }

  def main(args: Array[String]): Unit = {
    readTextFile
    println("==================================")
    readNetSource
    println("==================================")
    writeTextFile
  }
}