Scala语言简介

Scala是一种多范式的编程语言,其设计的初衷是要集成面向对象编程和函数式编程的各种特性。Scala运行于Java平台(Java虚拟机),并兼容现有的Java程序。它也能运行于CLDC配置的Java ME中。目前还有另一.NET平台的实现,不过该版本更新有些滞后。Scala的编译模型(独立编译,动态类加载)与Java和C#一样,所以Scala代码可以调用Java类库(对于.NET实现则可调用.NET类库)。Scala包括编译器和类库,以及BSD许可证发布。
学习Scala编程语言,为后续学习Spark奠定基础。

Scala数据类型

① 数值类型:Byte,Short,Int,Long,Float,Double
Byte: 8位有符号数字,从-128 到 127
Short: 16位有符号数据,从-32768 到 32767
Int: 32位有符号数据
Long: 64位有符号数据

例如:
val a:Byte = 10
a+10
得到:res9: Int = 20
这里的res9是新生成变量的名字

val b:Short = 20
a+b
**注意:**在Scala中,定义变量可以不指定类型,因为Scala会进行类型的自动推导。

② 字符类型和字符串类型:Char和String
对于字符串,在Scala中可以进行插值操作
BigData-22:Scala基础
③ Unit类型:相当于Java中的void类型

BigData-22:Scala基础
④Nothing类型:一般表示在执行过程中,产生了Exception

BigData-22:Scala基础

Scala语法基础

一、循环语句
1、类似Java:for、while、do…while
2、使用foreach进行迭代(循环)

val list = List("Mary", "Tom", "Mike")
		
		//for的第一种写法
		for (elem <- list) {
			println(elem)
		}
		System.out.println("************************")
		
		// 第二种写法
		// 加上判断条件,打印名字长度大于3的
		for (elem <- list if elem.length() > 3) {
			println(elem)
		}
		System.out.println("************************")
		
		// 第三种写法,使用yield关键字,产生一个新的集合
		// 把list中的每个元素变成大写
		val newList: List[String] = for{
			elem <- list
			s = elem.toUpperCase
		}yield (s)
		
		for (elem <- newList) {
			println(elem)
		}
		System.out.println("************************")
		
		
		// 使用while
		var i = 0
		while (i < list.length){
			println(list(i))
			i += 1
		}
		System.out.println("************************")
		
		var j = 0
		do {
			println(list(j))
			j += 1
		}while(j < list.length)
		System.out.println("************************")
		
		
		// 使用forEach进行迭代
		// foreach和map的区别:foreach没有返回值,map有返回值
		list.foreach(println)

二、Scala的函数参数
1、函数参数的求值策略
(1)call by value 定义: :
对函数实参求值,并且只求一次

(2)call by name 定义: :=>
函数的实参在函数体内部每次用到的时候,都会被求值

(3)复杂点的例子

			5-05	
			x是call by value, y是call by name
			def bar(x:Int,y: => Int):Int = 1
			
			定义一个死循环
			def loop():Int = loop
			
			调用bar函数,哪次会产生死循环?
			1、bar(1,loop)  正常返回1
			2、bar(loop,1)   会产生死循环
			
			分析原因!!

2、Scala中的函数参数的类型
	(1)默认参数
	     def func1(name:String="Tom"):String = "Hello " + name
			
	
	(2)代名参数:应用的场景:当有多个默认参数的时候,通过代名参数可以确定是给哪一个参数赋值
	     def func2(str:String="Good Morning ",name:String="Tom ",age:Int=20)
		 =
		 str + name + " and the age of " + name + " is " + age
		 
		 调用一下
		 func2()
		 func2(name="abcd")  把abcd付给name参数
	
	
	(3)可变参数
		scala> //可变参数

		scala> //求多个数字的和

		scala> def sum(args:Int*) = {
			 |     var result = 0
			 |     for(s <- args) result += s
			 |     result
			 | }
		sum: (args: Int*)Int

		scala> //调用

		scala> sum(1,2,3)
		res4: Int = 6

		scala> sum(1,2,3,4,5)
		res5: Int = 15

三、懒值(lazy值):常量如果是lazy的,他的初始化就会被推迟,推迟到第一次使用该常量的时候

做一点铺垫:Spark的核心是RDD(数据集合),操作数据集合中的数据,需要使用算子(函数、方法)
			算子有两种
			1、Transformation:延时加载,不会触发计算
			2、Action:会触发计算
		scala> //lazy值 懒值

		scala> val x:Int = 10
		x: Int = 10

		scala> val y:Int = x + 1
		y: Int = 11

		scala> //上面的特点是立即执行计算

		scala> lazy val z:Int = x + 1
		z: Int = <lazy>

		scala> //常量z的初始化就会被推迟

		scala> //没 有发计算

		scala> z
		res6: Int = 11

再举一个例子:读文件
	(1)存在的文件
	(2)不存在的文件
		scala> val words = scala.io.Source.fromFile("d:\\temp\\student.txt").mkString
		words: String =
		1 Tom 23
		2 Mary 25
		3 Mike 24
		5 Jone 20
		6 Jerry 21

		scala> lazy val words = scala.io.Source.fromFile("d:\\temp\\student.txt").mkString
		words: String = <lazy>

		scala> words
		res7: String =
		1 Tom 23
		2 Mary 25
		3 Mike 24
		5 Jone 20
		6 Jerry 21

		scala> //读取一个不存在的文件

		scala> lazy val words = scala.io.Source.fromFile("d:\\temp\\aaa.txt").mkString
		words: String = <lazy>

		scala> //不会产生Exception

		scala> words
		java.io.FileNotFoundException: d:\temp\aaa.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>

四、简介:例外:Exception
类似Java:try…catch…finally
BigData-22:Scala基础
五、数组
1、数组的类型
(1)定长数组:Array
scala> // 定长数组: Array

		scala> val a = new Array[Int](10)
		a: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)

		scala> val b = new Array[String](5)
		b: Array[String] = Array(null, null, null, null, null)

		scala> val c = Array("Tom","Mary","Mike")
		c: Array[String] = Array(Tom, Mary, Mike)
	
	
	(2)变长数组:ArrayBuffer
			scala> import scala.collection.mutable.ArrayBuffer
			import scala.collection.mutable.ArrayBuffer

			scala> val d = ArrayBuffer[Int]()
			d: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()

			scala> //往变长数组中添加元素

			scala> d += 1
			res9: d.type = ArrayBuffer(1)

			scala> d += 2
			res10: d.type = ArrayBuffer(1, 2)

			scala> d += 3
			res11: d.type = ArrayBuffer(1, 2, 3)

			scala> //一次添加多个元素

			scala> d += (10,20,30)
			res12: d.type = ArrayBuffer(1, 2, 3, 10, 20, 30)			
			
			去掉最后的两个元素
			d.trimEnd(2)
			
			scala> //遍历数组

			scala> var a = Array("Tom","Mary","Mike")
			a: Array[String] = Array(Tom, Mary, Mike)

			scala> //使用for语句进行遍历

			scala> for( s<- a) println(s)
			Tom
			Mary
			Mike

			scala> //使用foreach

			scala> a.foreach(print)
			TomMaryMike
			
	解释一下:
	    myArray1.sortWith(_ > _) 
		写完整
		myArray1.sortWith((a,b)=>{if(a>b) true else false})
		
		匿名函数:(a,b)=>{if(a>b) true else false}    ----> 简写:_ > _
		把匿名函数作为了sortWith参数值 -----> 把sortWith叫做高阶函数(Scala中的函数式编程)
		
2、多维数组:和Java一样,通过数组的数组来实现

BigData-22:Scala基础
下表中为 Scala 语言中处理数组的重要方法,使用它前我们需要使用import Array._引入包。

序号 方法和描述
1 def apply( x: T, xs: T* ): Array[T]创建指定对象 T 的数组, T 的值可以是 Unit, Double, Float, Long, Int, Char, Short, Byte, Boolean。
2 def concat[T]( xss: Array[T]* ): Array[T]合并数组
3 def copy( src: AnyRef, srcPos: Int, dest: AnyRef, destPos: Int, length: Int ): Unit复制一个数组到另一个数组上。相等于 Java’s System.arraycopy(src, srcPos, dest, destPos, length)。
4 def empty[T]: Array[T]返回长度为 0 的数组
5 def iterate[T]( start: T, len: Int )( f: (T) => T ): Array[T]返回指定长度数组,每个数组元素为指定函数的返回值。以上实例数组初始值为 0,长度为 3,计算函数为a=>a+1scala>Array.iterate(0,3(a=>a+1)res1: Array[Int] = Array(0, 1, 2)
6 def fill[T]( n: Int )(elem: => T): Array[T]返回数组,长度为第一个参数指定,同时每个元素使用第二个参数进行填充。
7 def fill[T]( n1: Int, n2: Int )( elem: => T ): Array[Array[T]]返回二数组,长度为第一个参数指定,同时每个元素使用第二个参数进行填充。
8 def ofDim[T]( n1: Int ): Array[T]创建指定长度的数组
9 def ofDim[T]( n1: Int, n2: Int ): Array[Array[T]]创建二维数组
10 def ofDim[T]( n1: Int, n2: Int, n3: Int ): Array[Array[Array[T]]]创建三维数组
11 def range( start: Int, end: Int, step: Int ): Array[Int]创建指定区间内的数组,step 为每个元素间的步长
12 def range( start: Int, end: Int ): Array[Int]创建指定区间内的数组
13 def tabulate[T]( n: Int )(f: (Int)=> T): Array[T]返回指定长度数组,每个数组元素为指定函数的返回值,默认从 0 开始。以上实例返回 3 个元素:scala> Array.tabulate(3)(a => a + 5)res0: Array[Int] = Array(5, 6, 7)
14 def tabulate[T]( n1: Int, n2: Int )( f: (Int, Int ) => T): Array[Array[T]]返回指定长度的二维数组,每个数组元素为指定函数的返回值,默认从 0 开始。

六、映射:就是的对,用Map来表示
scala> //创建一个Map(映射)

	scala> //学生的成绩

	scala> val scores = Map("Tom"->80,"Mary"->85,"Mike"->82)
	scores: scala.collection.immutable.Map[String,Int] = Map(Tom -> 80, Mary -> 85, Mike -> 82)

	scala> //Scala中,映射有两种  1、不可变的Map  2、可变的Map

	scala> //定义一个可变的Map
	scala> //保存学生的语文成绩
	scala> //有不同写法

	scala> val chinese = scala.collection.mutable.Map(("Alice",80),("Bob",95),("Mary",75))
	chinese: scala.collection.mutable.Map[String,Int] = Map(Bob -> 95, Alice -> 80, Mary -> 75)

	scala> //映射的操作
	scala> //1、获取映射中的值
	scala> chinese("Bob")
	res19: Int = 95

	scala> chinese.get("Bob")
	res20: Option[Int] = Some(95)

	scala> //2、获取一个不存在的值

	scala> chinese("Tom")
	java.util.NoSuchElementException: key not found: Tom
	  at scala.collection.MapLike$class.default(MapLike.scala:228)
	  at scala.collection.AbstractMap.default(Map.scala:59)
	  at scala.collection.mutable.HashMap.apply(HashMap.scala:65)
	  ... 32 elided

	scala> //先判断一下 ,key是否存在

	scala> if(chinese.contains("Tom")){
		 |    chinese("Tom")
		 | }else{
		 |    -1
		 | }
	res22: Int = -1

	scala> //可以简写

	scala> chinese.getOrElse("Tom",-1)
	res23: Int = -1

	scala> chinese.getOrElse("Alice",-1)
	res24: Int = 80
	
	scala> //更新映射中的值:必须是可变的映射

	scala> chinese("Bob")
	res25: Int = 95

	scala> chinese("Bob") = 100

	scala> chinese("Bob")
	res27: Int = 100

	scala> //如何进行迭代?类似数组

	scala> //可以使用for ,foreach

	scala> for(s <- chinese) println(s)
	(Bob,100)
	(Alice,80)
	(Mary,75)

	scala> chinese.foreach(println)
	(Bob,100)
	(Alice,80)
	(Mary,75)

七、元组:Tuple
1、复习一下:Tuple在Pig中、在Storm中都用到了
2、Scala的Tuple:是不同类型的值的集合
scala> //Tuple3代表的是有三个元素

	scala> val t2 = Tuple2(2,"World")
	t2: (Int, String) = (2,World)

	scala> //访问Tuple中的元素

	scala> t1.
	_1   _3         copy     hashCode   productArity     productIterator   toString   zipped
	_2   canEqual   equals   invert     productElement   productPrefix     x

	scala> t1._1
	res30: Int = 1

	scala> t1._2
	res31: Double = 3.14

	scala> t1._3
	res32: String = Hello

	scala> //如何遍历Tuple中的元素

	scala> //首先使用productIterator生成再遍历

	scala> t1.productIterator.foreach(println)
	1
	3.14
	Hello

**注意:**要遍历Tuple中的元素,需要首先生成对应的迭代器。不能直接使用for或者foreach。

Scala的面向对象:类似Java

一、面向对象的基本概念
1、封装:类class
2、继承
3、多态

(1)当定义属性是private时候,scala会自动为其生成对应的get和set方法
(2) 如果只希望get方法,不生成set方法,可以将属性定义为val常量
(3)如果希望不能直接被外部类访问(即希望不要生成get和set方法),可以使用private[this]修饰类或者属性

二、定义类:关键字class
举例:创建一个学生类

三、内部类

四、类的构造器:两种
1、主构造器:和类的声明在一起,并且一个类只有一个主构造器
2、辅助构造器:一个类可以有多个辅助构造器,通过关键字this

五、Object对象:相当于Java中的static
1、Object中的内容都是静态的
2、Scala中,没有静态修饰符static
3、如果class的名字,跟object的名字一样,这时候就把这个object叫做类的伴生对象
4、举例
(1)使用object实现单例模式:一个类只有一个对象
如果在Java中,构造器定义为private,提供getInstance方法

	(2)使用App对象:应用程序对象
			好处:可以省略main方法

六、apply方法:可以省略new关键字,根据自己的需要进行初始化
apply方法必须写在伴生对象中
BigData-22:Scala基础
scala> //创建一个数组

scala> var myarray = Array(1,2,3)   ----> 使用了apply方法
myarray: Array[Int] = Array(1, 2, 3)

scala> //本质就是创建一个Array对象

scala> //省略了new关键字

七、继承:
1、跟Java一样,使用关键字extends
2、抽象类、抽象字段

八、特质(trait):类似Java中的抽象类,并且支持多重继承
本质:就是抽象类,特点:支持多重继承
BigData-22:Scala基础

九、包和包对象:
包可以包含类、对象和特质,但不能包含函数或者变量的定义。很不幸,这是Java虚拟机的局限。
把工具函数或者常量添加到包而不是某个Utils对象,这是更加合理的做法。Scala中,包对象的出现正是为了解决这个局限。
Scala中的包对象:常量,变量,方法,类,对象,trait(特质),包

BigData-22:Scala基础

十、scala中文件访问
BigData-22:Scala基础

Scala的函数式编程:Scala是一个多范式的编程语言

举例:使用Spark执行WordCount
sc是Spark的一个对象,SparkContext这个对象非常重要

sc.textFile("hdfs://bigdata111:9000/input/data.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).collect

一、回顾:Scala中的函数:是头等公民
关键字:def

二、匿名函数:没有名字的函数
scala> //定义一个匿名函数

scala> (x:Int) => x*3
res1: Int => Int = <function1>

scala> //调用匿名函数

scala> //定义一个 数组,把数组中的每个元素乘以3

scala> //Array(1,2,3) 把Array中的每个元素作为x参数值,传递给匿名函数

scala> Array(1,2,3).map((x:Int) => x*3)
res2: Array[Int] = Array(3, 6, 9)

scala> //把(x:Int) => x*3 作为了map的参数值

三、高阶函数(带有函数参数的函数):把一个函数作为另一个函数的参数值
BigData-22:Scala基础
四、高阶函数示例
BigData-22:Scala基础
(*)map:相当于一个循环,对某个集合中的每个元素进行操作(就是接受一个函数),返回一个新的集合

	         val numbers = List(1,2,3,4,5,6,7,8,9,10)
			 numbers.map((i:Int)=>i*2)
			 简写 numbers.map(_ * 2)
(*)foreach:相当于一个循环,对某个集合中的每个元素进行操作(就是接受一个函数),不返回结果
         numbers.foreach((i:Int)=>i*2)


(*)filter: 过滤,选择满足条件的数据
		查询能够被2整除的数字
		numbers.filter((i:Int)=> i%2==0) 如果是true,就返回结果

(*)zip: 合并集合
		List(1,2,3).zip(List(4,5,6))


(*)partition: 根据断言(就是条件,通过一个匿名函数来实现)的结果,来进行分区
		举例:把能够被2整除的分成一个区,不能整除的分成另一个区
		numbers.partition((i:Int)=> i%2==0)

(*)find: 查找第一个满足条件(断言)的元素
        查询第一个能够被3整除的数字
		numbers.find(_%3 == 0)

(*)flatten:把嵌套的结构展开
		List(List(2, 4, 6, 8, 10),List(1, 3, 5, 7, 9)).flatten

(*)flatMap 相当于 map + flatten
		var myList = List(List(2, 4, 6, 8, 10),List(1, 3, 5, 7, 9))
		myList.flatMap(x=> x.map(_*2))
		结果 res16: List[Int] = List(4, 8, 12, 16, 20, 2, 6, 10, 14, 18)
		
		过程 (1)将List(2, 4, 6, 8, 10)和List(1, 3, 5, 7, 9)调用x=> x.map(_*2)
		     (2)再合并成一个List

五、概念:闭包、柯里化

  1. 闭包:就是函数的嵌套,即:
    在一个函数定义中,包含另外一个函数的定义;
    并且在内函数中可以访问外函数中的变量。
scala> //闭包:函数的嵌套

		scala> def mulBy(factor:Double)=(x:Double)=> x* factor
		mulBy: (factor: Double)Double => Double

		scala> //调用

		scala> //1、乘以3的操作,因子=3

		scala> val triple=mulBy(3)
		triple: Double => Double = <function1>

		scala> //值函数

		scala> triple(10)
		res0: Double = 30.0

		scala> //2、乘以0.5的操作 factor=0.5

		scala> val half = mulBy(0.5)
		half: Double => Double = <function1>

		scala> half(10)
		res1: Double = 5.0

BigData-22:Scala基础
2. 柯里化:Currying
3. 柯里化函数(Curried Function)是把具有多个参数的函数转换为一条函数链,每个节点上是单一参数。
BigData-22:Scala基础
BigData-22:Scala基础

相关文章: