Contents

Scala

Contents

基于Scala2.11

01.Scala入门

1

  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
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
1.Scala运行机制
	-先编译,再解释
	-.scala源文件-->编译器scalac-->.class字节码-->JVM(不同的平台)

2.伴生对象
	-在Scala中没有static关键字,通过伴生对象模拟实现类似静态的功能
	-伴随类产生对象,伴生对象所伴随的类称为伴生类
	-语法: object + 类名
	-底层会生成两个字节码文件,一个是伴生类,另外一个是伴生对象所属类
	-伴生类和object 后面加的名字一样,如果不显示声明,在通过object定义伴生对象的时候,会自动生成
	-其实伴生对象是伴生对象所属类中的一个单例对象
	-建议:以后在开发的过程中,如果使用到了类似static的属性和或者方法的时候,应该定义在伴生对象中

3.Scala中的注释
	-单行注释	//
	-多行注释	/* */
	-文档注释	/** */
		scaladoc -d 目录 源文件

4.变量和常量
	-final(Java)
	-var 变量 
	-val 常量
	-语法
		Java:	数据类型 变量名 = 值	int a = 10
		Scala:	var|val	名:数据类型 = 值

5.标识符
	-程序员可以自己命名的地方
	-命名规则
		*和Java一样
			>包含字母、数字、下划线以及货币符号
			>数字不能应用于首字符
			>不能是关键字以及保留字
			>不能含有空格
		*如果要以关键字命名,可以使用反引号将关键字括起来
		*以操作符开头,后面跟的是其它操作符 

6.字符串输出方式
	-以 “+” 进行拼接
	-printf(%s %d)
	-字符串模板(插值字符串),将字符串保留格式,原样输出
		""" """
		stripMargin 让字符串顶行,需要在每一行字符串行首加|
	-如果在输出字符串的时候,需要引用外部变量,可以使用${}获取,在字符串前加s
		
7.获取用户键盘上的输入
	StdIn.readXXX

8.数据类型(重点)
	-Java语言的数据类型
		*基本数据类型(8种)  byte、short、int、long、float、double、char、boolean
		*引用类型	

	-Scala语言的数据类型
		*最顶层父类Any
			>值类型   AnyVal
			>引用类型 AnyRef			

		*几种特殊的类型
			>Unit	只有一个实例    ()
			>Null	只有一个实例	null   不能赋值给值类型
			>Nothing   在方法不明确返回值类型的时候,可以使用Nothing

9.类型转换
	-小精度类型数据 -> 大精度类型 	自动类型转换

	-大精度类型数据 -> 小精度类型   强制类型转换 toXXX

	-自动类型提升	参与运算的数据,会自动提升为较高的类型之后,再进行运算
		byte -> short ->int ->long ->float ->double
			    char

10.Scala中的比较运算符
	- ==和equals效果相同,都是比较内容是否相同
	- eq比较的对象的地址
	-没有 ++ 以及--运算符
	-在Scala中没有运算符,所有的运算符都是方法

11.流程控制
	-顺序流程
	-分支流程|选择流程
		*单分支
			if(条件表达式){
				语句块	
			}
		*双分支
			if(条件表达式){
				语句块1
			}else{
				语句块2
			}
		*多分支
			if(条件表达式1){
				语句块1
			}else if(条件表达式2){
				语句块2
			}else if(条件表达式3){
				语句块3
			}...else{
				以上判断都没有满足,执行else语句块中的内容
			}

	-循环流程
		*范围数据循环	1 to 10   1 until 10  --->Range集合

		*循环守卫  for(i <- 1 to 10;if i!= 2)
			在循环过程中,进行判断

		*循环步长  for(i <- 1 to 10 by 2)

		*循环嵌套 for(外层循环;内层循环){}

		*引入变量,在定义循环变量的时候,同时定义一个普通变量,这个变量受循环变量影响

	-while和dowhile区别
		*while循环,执行0~n
			while(循环条件){

			}
		*do...while循环,执行1~n
			do{
				循环体
			}while(循环条件)

	-循环中断
		*在Scala中没有continue和break关键字
		*要想实现continue的效果,通过循环守卫即可实现
		*要想实现break,跳出整个循环的效果
			-可以自己抛出异常,实现中断
			-可以使用Scala提供的方法
				Breaks.breakable   Breaks.break  底层也是通过抛出异常的方式中断循环

		*导入类中的所有成员
			import scala.util.control.Breaks._

12.函数式编程
	-函数式编程的思想
		*Scala本身是一个多范式的编程语言,面向对象、面向函数
		*万物皆对象 + 万物皆函数

	-函数和方法的区别
		*定义位置
			定义在类的下函数,叫做方法
		*方法允许重载和重写,函数不允许

	-定义函数的基本语法
		def 函数名(参数列表):返回值类型={
			函数体
		}

		数据类型:AnyVal(Int)、AnyRef(String)、函数(函数参数=>返回值类型)、
				代码块( =>返回值类型)

	-函数参数
		*可变长参数	将可变长参数放到参数列表的最后
		*参数默认值	将有默认值的参数放到参数列表的后面
		*带名参数	在调用函数的时候,传递的实参可以指定参数的名字	

	-函数至简原则		
		(1)return可以省略,Scala会使用函数体的最后一行代码作为返回值
		(2)如果函数体只有一行代码,可以省略花括号
		(3)返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)
		(4)如果有return,则不能省略返回值类型,必须指定
		(5)如果函数明确声明unit,那么即使函数体中使用return关键字也不起作用
		(6)Scala如果期望是无返回值类型,可以省略等号
		(7)如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加
		(8)如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略
		(9)如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略
	
	-高阶函数
		*函数的更高级的用法,在Scala中,函数是作为一等公民存在
		*函数可以作为值进行传递
			def test1():Unit={
				println("XXX")
			}
			var f = test1()  //这个时候是将test1执行的结果赋值给f
			var f = test1 _  //这个时候,将test1函数本身作为值赋给了f
			f() //调用函数

		*函数可以作为参数传递
			def f1(f:(Int,String)=>Unit):Unit={}

			def f2(age:Int,name:String):Int={}

			f1(f2 _) //将函数作为参数传递
			f1(f2) //因为编译器可以根据f1的参数类型推断出f2是一个函数,所以下划线可以省

			//使用lamda 表达式,使用匿名函数
			f1((x:Int,y:String)=>{println(x + y)})

			//匿名函数的至简原则
			(1)参数的类型可以省略,会根据形参进行自动的推导
				f1((x,y)=>{println(x + y)})
			(2)类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参数超过1的永远不能省略圆括号。
			(3)匿名函数如果只有一行,则大括号也可以省略
				f1((x,y)=>println(x + y))
			(4)如果参数只出现一次,则参数省略且后面参数可以用_代替
				f1(println(_ + _))


		*函数可以作为返回值返回	
			def f1()={
				var a:Int = 10
				def f2()={
					println(a)
				}
				f2 _
			}

			f1()()

	-闭包
		*通过函数的嵌套调用体现
		*内部函数(f2),访问外部函数(f1)的局部变量(a),会自动延长外部函数局部变量的生命周期,与内部函数形成一个闭合的效果,称为闭包

		*闭包 = 外部函数局部变量  + 内层函数

	-柯里化
		*前提:闭包
		*语法
			def f1()(){

			}
		*作用
			>简化函数嵌套编写
			>将一个函数中的多个参数,拆分为多个参数列表,更有针对性

	-控制抽象
		*值调用
			传递的是函数执行完毕之后的结果

		*名调用
			传递的是代码块
			
			代码块类型:	=>返回值类型		
	
	-案例:自定义while循环
		while(循环条件){循环体}	

		def mywhile(condition: =>Boolean)(op: =>Unit)={
			if(condition){
				op
				mywhile(condition)(op)
			}
		}		

	-惰性函数

13.面向对象
	-Scala中的包
		*声明
			>和Java一样的声明方式
			>嵌套的声明方式
				&一个源文件中可以定义多个package
				&子包中的类,如果要想访问父包中的内容,不需要导包
		*导包

	-在自然界中,只要是客观的都是对象
	-对大量对象共性进行抽象--类
		*有什么(属性)
		*能做什么(方法)
	-在Scala语言中,类是创建对象的模板

	-Scala中对象创建的两种方式
		*new 类名--->构造器
			>主构造器   在定义类的同时,定义类主构造器
				&参数没有任何修饰,就相当于局部变量
				&参数还可以使用var或者val进行修饰,相当于属性
			>辅助构造器
				&def this()
				&在每一个辅助构造器中,必须直接或者间接的调用主构造器
				&辅助构造器可以定义多个(重载)
		*类名()	--->apply方法

	-面向对象的三大特性
		*封装
			>属性私有化,提供公开的获取|设置属性的方法
			>Scala语言中,属性定义的时候,我们不需要加任何访问修饰符,默认使用public修饰,但是底层生成的代码,会用private修饰属性,同时提供公开的获取以及设置属性的方法;
			>如果为了和某些框架兼容,生成get|set方法,需要在定义属性的时候,在属性前加@BeanProperty 

		*继承
			>子类继承父类的非私有属性和方法
			>和Java继承一样,Scala也是单继承
			>通过extends关键字完成继承
			>存在继承关系,对象的构建顺序
				先调用父类构造,再调用子类构造

		*多态
			>同一个对象的多种不同形态
			>父类引用指向了子类对象,特质指向实现类
			>只能调用其引用类型中定义的方法
			>在运行的时候,会调用其子类中覆盖的方法
			>静态绑定(编译器绑定)和动态绑定(运行期绑定)

	-抽象属性和抽象方法
		*抽象属性,在Scala中,属性也可以定义为抽象的
		*抽象方法 只有方法的声明,没有实现

	-抽象类
		*如果类声明为抽象类,那么其中的抽象属性和抽象方法应在子类中实现
		*如果子类也不能处理父类 中的抽象内容,那么子类也应该定义为抽象的
		*重写非抽象方法需要用override修饰,重写抽象方法则可以不加override
		*属性重写只支持val类型,而不支持var
		*Scala中属性和方法都是动态绑定,而Java中只有方法为动态绑定


	-访问权限
		*Java:私有的->默认的->受保护的->公开的
		
		*Scala 中属性和方法的默认访问权限为public,但Scala中无public关键字。
		*private为私有权限,只在类的内部和伴生对象中可用。
		*protected为受保护权限,Scala中受保护权限比Java中更严格,同类、子类可以访问,同包无法访问。
		*private[包名]增加包访问权限,包名下的其他类也可以使用

	-特质
		*对应Java的接口
		*使用trait关键字声明
		*如果一个类具有某个特质,我们称之为混入特质
		*混入特质
			不存在父类:	类名 extends 特质1 with 特质2
			存在继承关系:	类名 extends 父类 with 特质1 with 特质2

	-特质叠加顺序
		class MyClass17 extends MySQLOperation with  HDFSOperation{
		我的操作是 向HDFS中-向MySQL数据库-插入数据

		*列出第一个混入的特质的继承关系 ,作为临时顺序
			MySQLOperation->Operation,

		*列出第二个混入的特质的继承关系,放到临时顺序的前面,已经出现的特质不在出现
			HDFSOperation -> MySQLOperation->Operation

		*将子类放到临时叠加顺序的第一个位置
			MyClass ->HDFSOperation -> MySQLOperation->Operation

		*super关键字,不是指向父特质中的方法了,而是调用临时叠加顺序中的下一个特质中的方法	
			



下划线使用场景
	-标识符命名
	-将函数作为值进行传递
	-匿名函数中,如果参数只出现一次,则参数省略且后面参数可以用_代替
	-导包
		*通配符导入:import java.util._
		*导入类中的所有成员
		*屏蔽类:import java.util.{ArrayList =>_,_}

	-定义类的时候,给属性赋默认值
		var name:String = _

----------------------------------------------------------
1.Java的集合
	-Collection
		*存放的是单值类型
		*继承Iterable(可迭代的)
		*List集合
			>有序、可重复(有序不是排序,指的是集合中的元素有先来后到的顺序,有序意味着集合中的元素有索引)

			>ArrayList
				&底层实现是数组
				&数组实现优缺点
					#优点:查询效率高
					#缺点:增删效率低
					#因为数组中元素是连续的,每个元素都有对应的下标,根据下标很快定位数组中的元素,所以查询效率高;因为是连续的,在做增删操作的时候,为了保证连续性,会涉及移位,所以增删效率低

			>LinkedList
				&底层实现是双向链表
				&链表实现优缺点
					#优点:增删效率高
					#缺点:查询效率低
					#因为链表中的元素,在内存中不是连续存储的,当要查找链表中的元素的时候,需要进行全链表扫描,所以查询效率低;在做增删操作的时候,不需要移位,只需要改变链表的指向即可,所以增删效率高。
			>Vector
				&底层实现是数组,线程安全的,效率低,很少用

		*Set集合
			>无序、不可重复
			>HashSet
				&底层是HashMap
			>SortedSet->TreeSet
				&底层是TreeMap

	-Map
		*存放的是kv类型的键值对
		*HashMap
			>底层是哈希表(散列表)
			>不是纯数组,也不是纯链表,是数组和链表的结合体
			
		*TreeMap
			>底层是可排序二叉树

2.Scala集合
	-分三大类 序列Seq、集Set、键值对Map
	-可变和不可变
		*指的是集合进行添加或者删除操作
		*可变,会在原来集合的基础之上进行添加或者删除
			scala.collection.mutable
		*不可变,在进行添加或者删除的时候,会创建新的集合
			scala.collection.immutable

	-不可变用操作符,可变用方法

	-数组
		*不可变数组 Array
		*可变数组	ArrayBuffer
		*不可变和可变数组之间的转换
	
	-序列Seq(有序、可重复)
		*不可变的序列 List
		*可变序列 ListBuffer
		*::
		*:::
		*Nil代表一个空集合

	-Set集合(无序、不能重复)

	-Map集合(以键值对的形式存放数据)

	-元组

3.Scala集合常用的函数
	-基本属性和常用操作
		(1)获取集合长度	length
		(2)获取集合大小	size
		(3)循环遍历		foreach
		(4)迭代器			iterator
		(5)生成字符串		mkString
		(6)是否包含		contains

	-衍生集合
		(1)获取集合的头		head	
		(2)获取集合的尾(不是头的就是尾)	tail
		(3)集合最后一个数据	last
		(4)集合初始数据(不包含最后一个)	init
		(5)反转	reverse			
		(6)取前(后)n个元素	take
		(7)去掉前(后)n个元素	drop
		(8)并集	union
		(9)交集	intersect
		(10)差集	diff
		(11)拉链	zip
		(12)滑窗	sliding

	-集合计算的初级函数
		(1)求和	sum
		(2)求乘积	product
		(3)最大值	max
		(4)最小值	min
		(5)排序	sorded|sortBy|sortWith

	-集合计算的高级函数
		(1)过滤 filter
			遍历一个集合并从中获取满足指定条件的元素组成一个新的集合
		(2)转化/映射	map
			将集合中的每一个元素映射到某一个函数
		(3)扁平化	flatten
			将集合中的整体拆分为一个一个的元素

		(4)扁平化+映射	flatMap
			注:flatMap相当于先进行map操作,在进行flatten操作
			集合中的每个元素的子元素映射到某个函数并返回新集合

		(5)分组	groupBy	
			按照指定的规则对集合的元素进行分组

		(6)简化(规约)
			-reduce|reduceLeft|reduceRight   
			-集合内元素进行聚合
			-通过指定的逻辑将集合中的数据进行聚合,从而减少数据,最终获取结果。
			
		(7)折叠  
			-fold|foldLeft|foldRight	
			-简化的一种特殊情况,集合外元素和集合内元素进行聚合。