Scala函数的参数
Scala中,有两种函数参数的求值策略
Call By Value:对函数实参求值,且仅求一次
Call By Name:函数实参每次在函数体内被用到时都会求值
我们来分析一下,上面两个调用执行的过程:
一份复杂一点的例子:
Scala中的函数参数
默认参数
代名参数
可变参数
(1)默认参数
当你没有给参数赋值的时候,就使用默认值
scala> def fun1(name:String) : String = "Hello " + name
fun1: (name: String)String
scala> fun1("Tom")
res0: String = Hello Tom
scala> fun1()
<console>:13: error: not enough arguments for method fun1: (name: String)String.
Unspecified value parameter name.
fun1()
^
scala> def fun1(name:String="Andy") : String = "Hello " + name
fun1: (name: String)String
scala> fun1("Tom")
res2: String = Hello Tom
scala> fun1()
res3: String = Hello Andy
(2)代名参数
当有多个默认参数的时候,通过代名参数可以确定给哪个参数赋值
scala> def fun2(str:String="Good Morning ",name:String=" Tom ",age:Int=20)=str + name + " and the age of " + name + " is" + age
fun2: (str: String, name: String, age: Int)String
scala> fun2()
res4: String = Good Morning Tom and the age of Tom is20
scala> fun2(name= " Mary ")
res5: String = Good Morning Mary and the age of Mary is20
(3)可变参数
类似于java中的可变参数。即 参数数量不固定。
举例:求多个数字的和:
def sum(x:Int,y:Int) = x+y
def sum(x:Int,y:Int,z:Int) = x+y+z
def sum(args:Int*) = {
var result = 0
for(x <- args) result += x
result
}
scala> def sum(args:Int*) = {
| var result = 0
| for(x <- args) result += x
| result
| }
sum: (args: Int*)Int
scala> sum(1,2,3)
res6: Int = 6
scala> sum(2,3)
res7: Int = 5
scala> sum(2,3,4,5,6,7)
res8: Int = 27
Scala的Lazy值(懒值)
当val被申明为lazy时,它的初始化将被推迟,直到我们首次对它取值。
一个更为复杂一点的例子:读取文件:
铺垫:Spark 核心 RDD (数据集合) 。操作数据集合中的数据时,我们使用算子(函数、方法)。
算子有两种:
1、Transformation : 延时计算,不会立刻触发计算 T
2、Action : 触发计算 A
RDD.T.T.T.T.A
Transformation 用了 lazy值
定义:如果被lazy修饰了,他的初始化会被延迟,推迟到第一次使用该常量、变量的时候。
scala> val x : Int = 10
x: Int = 10
scala> val y : Int = x + 1
y: Int = 11
定义后会立即触发计算
scala> lazy val z : Int = x + 1
z: Int = <lazy>
初始化会被延迟,没有触发计算。当我们第一次使用z的时候,才会触发计算
scala> z
res9: Int = 11
举例:读文件
(1)读一个存在的文件
scala> val words = scala.io.Source.fromFile("H:\\tmp_files\\student.txt").mkString
words: String =
1 Tom 12
2 Mary 13
3 Lily 15
scala> lazy val words = scala.io.Source.fromFile("H:\\tmp_files\\student.txt").mkString
words: String = <lazy>
scala> words
res10: String =
1 Tom 12
2 Mary 13
3 Lily 15
(2)读不存在的文件
scala> val words = scala.io.Source.fromFile("H:\\tmp_files\\studkjslfkdjlskdjfldent.txt").mkString
java.io.FileNotFoundException: H:\tmp_files\studkjslfkdjlskdjfldent.txt (系统找不到指定的文件。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at scala.io.Source$.fromFile(Source.scala:91)
at scala.io.Source$.fromFile(Source.scala:76)
at scala.io.Source$.fromFile(Source.scala:54)
... 32 elided
scala> lazy val words = scala.io.Source.fromFile("H:\\tmp_files\\stude932409230ijdosijf;oisnt.txt").mkString
words: String = <lazy>
scala> words
java.io.FileNotFoundException: H:\tmp_files\stude932409230ijdosijf;oisnt.txt (系统找不到指定的文件。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at scala.io.Source$.fromFile(Source.scala:91)
at scala.io.Source$.fromFile(Source.scala:76)
at scala.io.Source$.fromFile(Source.scala:54)
at .words$lzycompute(<console>:11)
at .words(<console>:11)
... 32 elided
异常的处理
Scala异常的工作机制和Java或者C++一样。直接使用throw关键字抛出异常。
mport java.io.FileNotFoundException
/**
* Exception
*/
object DemoEx {
def main(args: Array[String]): Unit = {
//使用 try catch finally 来捕获异常
try{
println("--------try catch finally")
val words = scala.io.Source.fromFile("E:\\test\\abc\\test.txt").mkString
}catch {
case ex : FileNotFoundException => {
println("FileNotFoundException")
}case ex : IllegalArgumentException => {
println("IllegalArgumentException")
}case _: Exception => {
println("Exception")
}
}finally {
println("This is finaly")
}
}
}
自定义函数
1、求阶乘 递归
scala> def myFactor(x:Int) : Int = {
| if (x <= 1)
| 1
| else
| x*myFactor(x-1)
| }
myFactor: (x: Int)Int
注意:没有return语句。函数的最后一句话就是函数的返回值。
上面例子中,有函数的分支,1 和 x*myFactor(x-1) 都有可能是函数的最后一句话。
相当于在前面都有return
scala> myFactor(5)
res11: Int = 120
2、求输入的年份是否是闰年
普通闰年:能被4整除但不能被100整除的年份为普通闰年(如 2004年就是闰年,1999年不是闰年)
世纪闰年:能被400整除的为世纪闰年(如 2000年就是世纪闰年 1900年不是世纪闰年)
scala> def isLeapYear(x:Int) = {
| if((x%4==0 && x%100 != 0) || x % 400 ==0) true
| else false
| }
isLeapYear: (x: Int)Boolean
scala> isLeapYear(2008)
res12: Boolean = true
scala> isLeapYear(2009)
res13: Boolean = false
数组
1、数组的类型
(1)定长数组:Array
scala> val a = new Array[Int](10)
a: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
scala> val a = new Array[String](10)
a: Array[String] = Array(null, null, null, null, null, null, null, null, null, null)
scala> val a = Array("Tom","Andy","Lily")
a: Array[String] = Array(Tom, Andy, Lily)
scala> val a = Array("Tom","Andy","Lily",1)
a: Array[Any] = Array(Tom, Andy, Lily, 1)
scala> val a : Array[String] = Array("Tom","Andy","Lily",1)
<console>:11: error: type mismatch;
found : Int(1)
required: String
val a : Array[String] = Array("Tom","Andy","Lily",1)
(2)变长数组:ArrayBuffer
scala> import scala.collection.mutable._
import scala.collection.mutable._
scala> val a = ArrayBuffer[Int]()
a: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()
scala> a
res13: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()
scala> a += 1
res14: a.type = ArrayBuffer(1)
scala> a += 2
res15: a.type = ArrayBuffer(1, 2)
scala> a += 10
res16: a.type = ArrayBuffer(1, 2, 10)
scala> a += (100,200,300)
res17: a.type = ArrayBuffer(1, 2, 10, 100, 200, 300)
scala> a.
++ combinations groupBy mapResult reverse to
++: companion grouped max reverseIterator toArray
++= compose hasDefiniteSize maxBy reverseMap toBuffer
++=: contains hashCode min runWith toIndexedSeq
+: containsSlice head minBy sameElements toIterable
+= copyToArray headOption mkString scan toIterator
+=: copyToBuffer indexOf nonEmpty scanLeft toList
- corresponds indexOfSlice orElse scanRight toMap
-- count indexWhere padTo segmentLength toSeq
--= diff indices par seq toSet
-= distinct init partition size toStream
/: drop inits patch sizeHint toString
:+ dropRight insert permutations sizeHintBounded toTraversable g
:\ dropWhile insertAll prefixLength slice toVector
<< endsWith intersect prepend sliding transform
WithFilter equals isDefinedAt prependAll sortBy transpose
addString exists isEmpty product sortWith trimEnd
aggregate filter isTraversableAgain readOnly sorted trimStart
andThen filterNot iterator reduce span union
append find last reduceLeft splitAt unzip
appendAll flatMap lastIndexOf reduceLeftOption startsWith unzip3
apply flatten lastIndexOfSlice reduceOption stringPrefix update
applyOrElse fold lastIndexWhere reduceRight sum updated
canEqual foldLeft lastOption reduceRightOption tail view
clear foldRight length reduceToSize tails withFilter
clone forall lengthCompare remove take zip
collect foreach lift repr takeRight zipAll
collectFirst genericBuilder map result takeWhile zipWithIndex
去掉最后两个元素
scala> a.trimEnd(2)
scala> a
res19: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 10, 100)
遍历数组:
scala> val a = Array("Tom","Andy","Lily")
a: Array[String] = Array(Tom, Andy, Lily)
scala> for(s <- a) println(s)
Tom
Andy
Lily
scala> a.foreach(println)
Tom
Andy
Lily
数据常见操作:
scala> val myarray = Array(1,2,7,8,10,3,6)
myarray: Array[Int] = Array(1, 2, 7, 8, 10, 3, 6)
scala> myarray.max
res22: Int = 10
scala> myarray.min
res23: Int = 1
scala> myarray.sortWith(_>_)
res24: Array[Int] = Array(10, 8, 7, 6, 3, 2, 1)
scala> myarray.sortWith(_<_)
res25: Array[Int] = Array(1, 2, 3, 6, 7, 8, 10)
解释 myarray.sortWith(_>_)
sortWith(以某种 规则 进行排序)
完整:myarray.sortWith((a,b) => {if(a>b) true else false})
(a,b) => {if(a>b) true else false} 是一个函数。匿名函数:没有名字 传入两个参数 a b 返回值 bool。
(a,b) => {if(a>b) true else false} 简写 _>_
匿名函数作为sortWith的参数 高级函数(函数式编程)
多维数组
多维数组
(1)和Java一样,通过数组的数组来实现
定义一个固定长度的二维数组
scala> val matrix = Array.ofDim[Int](3,4)
matrix: Array[Array[Int]] = Array(
Array(0, 0, 0, 0),
Array(0, 0, 0, 0),
Array(0, 0, 0, 0))
scala> matrix(1)(2) = 10
scala> matrix
res27: Array[Array[Int]] = Array(
Array(0, 0, 0, 0),
Array(0, 0, 10, 0),
Array(0, 0, 0, 0))
(2)定义一个二维数组,其中每个元素是一个一维数组,但是其长度不固定
scala> val triangle = new Array[Array[Int]](10)
triangle: Array[Array[Int]] = Array(null, null, null, null, null, null, null, null, null, null)
scala> for( i <- 0 until triangle.length)
| triangle(i) = new Array[Int](i+1)
scala> triangle
res29: Array[Array[Int]] = Array(
Array(0),
Array(0, 0),
Array(0, 0, 0),
Array(0, 0, 0, 0),
Array(0, 0, 0, 0, 0),
Array(0, 0, 0, 0, 0, 0),
Array(0, 0, 0, 0, 0, 0, 0),
Array(0, 0, 0, 0, 0, 0, 0, 0),
Array(0, 0, 0, 0, 0, 0, 0, 0, 0),
Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
元组(Tuple)
元组是不同类型的值的聚集。
例如:val t = (1, 3.14, “Fred”) // 类型为Tuple3[Int, Double, java.lang.String]
这里:Tuple是类型,3是表示元组中有三个元素。
元组的访问和遍历:
Scala中的Tuple:是不同类型值的集合
scala> val t1 = Tuple(1,0.32,"Hello")
<console>:17: error: not found: value Tuple
val t1 = Tuple(1,0.32,"Hello")
^
scala> val t1 = Tuple3(1,0.32,"Hello")
t1: (Int, Double, String) = (1,0.32,Hello)
scala> val t1 = (1,0.32,"Hello")
t1: (Int, Double, String) = (1,0.32,Hello)
scala> val t1 = (1,0.32,"Hello",1,2,3,10)
t1: (Int, Double, String, Int, Int, Int, Int) = (1,0.32,Hello,1,2,3,10)
scala> t1.
_1 _3 _5 _7 copy hashCode productElement productPrefix
_2 _4 _6 canEqual equals productArity productIterator toString
scala> t1._1
res30: Int = 1
scala> t1._3
res31: String = Hello
如何遍历Tuple中的元素
注意:Tuple没有提供foreach函数,我们使用productIterator
遍历Tuple分成两步:
1、使用productIterator生成迭代器
2、遍历
scala> t1.productIterator.
++ corresponds foldRight max reduceLeft span toSeq
/: count forall maxBy reduceLeftOption sum toSet
:\ drop foreach min reduceOption take toStream
GroupedIterator dropWhile grouped minBy reduceRight takeWhile toString
addString duplicate hasDefiniteSize mkString reduceRightOption to toTraversable
aggregate exists hasNext next sameElements toArray toVector
buffered filter indexOf nonEmpty scanLeft toBuffer withFilter
collect filterNot indexWhere padTo scanRight toIndexedSeq zip
collectFirst find isEmpty partition seq toIterable zipAll
contains flatMap isTraversableAgain patch size toIterator zipWithIndex
copyToArray fold length product slice toList
copyToBuffer foldLeft map reduce sliding toMap
scala> t1.productIterator.foreach(println)
1
0.32
Hello
1
2
3
10
小案例
/**
*判断101-20之间有多少个的素数
*
* 程序分析:
* 判断素数的方法
* 用一个数分别去除2到sqrt(这个数),如果可以被整除,则表明次数不是素数,反之是素数
*
* 程序实现方法:
* 定义两层循环
* 第一层 101-200
* 第二层 2-sqrt(第一层循环的数)
*
* 举例:16
* 2循环到 sqrt(16)= 4
*
*
*/
//循环的嵌套
println("----------循环嵌套--------")
var index_inner = 0
var count = 0 //保存素数的个数
for (index_outer <- 101 until 200){
var b = false //标识是否可以被整除
breakable{
index_inner = 2
while (index_inner <= sqrt(index_outer)) {
if (index_outer % index_inner ==0){
//是素数
b = true
break
}
index_inner += 1
}
}
if (!b) count += 1
}
println("个数是:" + count)
}
}
/**
* 冒泡排序
*/
object DemoSort {
/**
*
* 算法分析:
* 1、比较相邻元素,如果第一个比第二个大,就交换。
* 2、对每一个相邻元素做相同工作,从左往右,第一轮遍历完之后,最后的元素会是最大的数。
* 3、针对所有元素重复以上步骤,除了已经排好的元素。
*
* 程序分析:
* 1、两层循环。
* 2、外层循环控制比较的次数。
* 3、内层循环控制到达的位置,也就是比较结束的位置。
*
*/
def main(args: Array[String]): Unit = {
println("---------冒泡排序--------")
var a = Array(1,5,3,8,7,9,2,4,6,34,65)
println("--------排序前----------")
a.foreach(println)
for (i <- 0 until a.length - 1){
for (j <- 0 until a.length -1 -i){
if (a(j) > a(j+1)){
//交换
var tmp = a(j)
a(j) = a(j+1)
a(j+1) = tmp
}
}
}
println("--------排序后---------")
a.foreach(println)
}
}