Scala基础教程:http://www.runoob.com/scala/scala-tutorial.html
值与变量(推荐使用val,第一选择使用val,如果业务需要,才允许使用var)
val和var的区别?
val: 值,赋值后,数据不可变
var: 变量,赋值后,数据可变
定义格式:
[var or val] name[:type] = [表达式(用大括号括起来的可以当做表达式)或者值/对象或者下划线]
下划线会给个默认值。
Scala表达式的返回值就是最后一行代码的执行结果,但是scala保留了return的含义,但是不推荐使用。
Unit: 类似java中的void,表示返回空类型
懒加载: lazy,指变量在第一次进行使用的时候进行初始化操作, 而且只有在第一次调用的时候会进行初始化
lazy val c = {
println("nihao")
12 + 3
}
Scala中默认一行一条语句,不需要使用分号";"进行代码的格式化操作, 针对跨行的语句,会自动进行推断,但是要求能够进行推断出来
lazy val c = {
val str = "yushu" +
"gerry"
println(str)
println("nihao")
12 + 3
}
String类型变量的写法:
val str = "hadoop spark"
val str = "hadoop spark \"mllib\"" 转义双引号
val str = """hadoop spark "mllib"""" 保留三个双引号中的所以引号
val str = """
hadoop spark "mllib"
spark core
"""
val str = """
|hadoop spark "mllib"
|spark core
|""".stripMargin
Scala的操作符:
基本和Java一样,操作符的优先级基本和java一样
特殊:
1. 不支持一元操作符中的++和--
2. 不支持三元/目操作符:(?:)
3. Scala中的所有操作符实质上就是函数,函数也可以写成操作符
所有以字母开头的操作符(函数)的优先级只比赋值操作符高
4. 基本上所有的操作符都是左连接的,但是如果函数是以冒号(:)开头的,操作符是右连接的
5. map进行循环的时候,可以匹配key/value,省略key/value的值的时候
==========Scala 判断 循环函数==================
IF-ELSE
语法和Java一样,可以替换三目操作符的功能
Scala不支持break和continue关键字,但是可以同Breaks类实现类似break的功能
While、Do-While
语法和Java一样
For
Scala不支持Java的for循环写法
for(item <- arr) {
....
}
============================================
===============Scala函数 =====================
函数是一等公民 ====> 可以独立存在,可以赋值给任何变量、可以出现任何地方(类中、对象中、函数中....)
scala> def max(x: Int, y: Int): Int = {
| if (x > y)
| x
| else
| y
| }
max: (x: Int, y: Int)Int
max:(Int, Int) => Int
表示输入参数列表为:(Int,Int),返回结果类型为:Int
函数的表示方式:f:T=>R, 一个函数f,输入参数为T,返回结果为R
如果一个函数在定义的时候,没有输入参数,可以给定空的参数列表也可以不给定(是否给定小括号), 如果一个函数的调用对于对象没有影响的情况下,可以选择不给定括号;但是当有影响的时候,也就是会改变对象的值的时候,一般建议给定小括号。
调用函数的时候是否给定括号和定义函数的时候一致即可
匿名函数
val max1 = max _
max1(4,5)
val max2 = (x: Int, y: Int) => {
if (x > y)
x
else
y
}
max2(4,5)
匿名函数:没有函数名称的函数,一般情况会将匿名函数赋值给一个变量来使用
(x: Int, y: Int) => {
if (x > y)
x
else
y
}
函数的调用过程中,默认情况是从左往右匹配参数列表,但是可以在调用的时候,强制给定参数列表的值
scala> max(4,5)
res33: Int = 5
scala> max(x = 4, y =5)
res34: Int = 5
scala> max(y = 5, x = 4)
res36: Int = 5
高阶函数
如果函数f有一个参数g,g是函数类型的,那么f就叫做高阶函数;
接收其他函数作为参数的函数,被称作高阶函数。
eg:
def f(g: T => R) {
// 代码
}
// 1. 可以不写数据类型,scala编译器会自动推断数据类型,根据定义的函数来进行推断
greeting("gerry", (name) => println(s"${name}, Hi"))
opera(1, 2, (a, b) => a + b)
// 2. 如果输入参数只有一个的情况下,可以省略小括号
greeting("gerry", name => println(s"${name}, Hi"))
// 3. 如果左侧的输入参数在右侧的代码体中都使用了,而且使用顺序和参数列表中的顺序一致,并且所有参数仅仅使用一次,那么可以使用下划线代替,输入参数列表就不用写了(要求使用下划线代替后没有异议)
greeting("gerry", println(_))
opera(1, 2, _ + _)
// 4. 如果右侧的函数体仅仅是调用其它已经存在的函数,而且传入的参数是所有左侧输入的参数列表中的参数,而且顺序一致,那么可以直接省略下划线
greeting("gerry", println)
===================Scala的常用高阶函数=============
map: 对传入的每个元素都进行映射,返回一个处理后的元素 Array(1, 2, 3, 4, 5).map(2 * _)
foreach: 对传入的每个元素都进行处理,但是没有返回值 (1 to 9).map("*" * _).foreach(println _)
filter: 对传入的每个元素都进行条件判断,如果对元素返回true,则保留该元素,否则过滤掉该元素 (1 to 20).filter(_ % 2 == 0)
reduceLeft: 从左侧元素开始,进行reduce操作,即先对元素1和元素2进行处理,然后将结果与元素3处理,
再将结果与元素4处理,依次类推,即为reduce;reduce操作必须掌握!spark编程的重点!!!
// 下面这个操作就相当于1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9
(1 to 9).reduceLeft( _ * _)
====================递归 ==========================
在函数内部调用函数自身进行解决问题
每一次递归会将允许代码添加到栈中,如果递归的深度太深的话,有可能出现OOM的异常
尾递归:对递归的一种优化方式,不会将每次的递归放到栈中
要求:最后返回的实递归代码
def f(n:Int):Int = {
if (n <= 1) 1
else f(n - 1) * n
}
def f(n:Int, m:Int = 1):Int = {
if (n <= 1) n * m
else f(n - 1, m * n)
}
def f(n:Int):Int = {
if (n <= 1) throw new RuntimeException("1")
else f(n - 1) * n
}
def f(n:Int, m:Int = 1):Int = {
if (n <= 1) throw new RuntimeException("1")
else f(n - 1, m * n)
}
=====================================================
集合中:优选选择使用不可变集合,业务需要才允许使用可变集合
数组
变长数组(ArrayBuffer)和数组(Array)
变长数组可以更改数组的大小(新增、删除数据、查、更改数据)
数组不支持数组大小的更改(查、更改数据)
数组下标从0开始,不能越界,如果访问下标异常的数据会抛出异常<ArrayIndexOutOfBoundsException>,使用小括号 + 下标的方式进行数据的获取,eg: arr(0) 获取下标为0的数组中的数据
数组 是集合中的一种数据类型,而元组不是集合中的类型
元组:
内部可以放不同数据类型的数据
下标从1开始,读取数据方式为:下划线+下标,eg: tuple._1表示获取第一个元素的数据
元组中的数据不允许进行修改操作,不允许修改元组的数据引用,至于数据内部是可以进行修改
元组中的数据类型可以是任何数据类型
注意:Scala中最多支持22元组
注意:可以通过函数->来创建一个二元组: (a,b) <==等价于==> a -> b
List
空链表: Nil
重点注意:List的相关API
Set:
无序不重复的集合
Map:
关联数组(key/value键值对的集合)
存储的数据是Key:Value键值对
Map中存储的数据可以看做是一个一个的二元组
集合注意事项:
-1. 集合分为可变集合和不可变集合
-2. 优先选择不可变集合使用
-3. 默认集合就是不可变集合
-4. 集合的相关的API
==============================================
Scala面向对象
作用域:可以放在属性、方法、class、object、trait上
public:默认,而且public不能写
protected:功能和java一样,但是scala不推荐使用
private: 功能和java一样
private[包名/this]: 分别表示包可用、当前类对象可用
class:类
类似于java中的类(单继承等等)
abstract class: 抽象类
类似于java中的抽象类
object:对象
scala中不支持static关键字 类似于java中单例对象,在jvm中只存在一份;所以object中的所有属性、方法均可以看成是staitc关键字修饰的
trait: 特质
当做接口来使用,但和Java的接口又有不同,这边可以有具体的方法实现
Scala中的类的继承是单继承的和java一样,构造的顺序和java一样
class的构造函数
默认构造函数为空
主构造函数是class类名后定义的一个括号 + class的{}中的所有内容
辅助构造函数是以this为名称的,而且没有返回值的方法/函数, 辅助构造函数必须调用主构造函数,而且必须是第一行
注意:将函数赋值给变量时,必须在函数后面加上空格和下划线
==============================================
object:
对象,为了解决scala中不能class中写static的问题的一方案
在jvm中只会存在一份,可以当做单例对象来使用
内部可以定义属性、方法等
伴生对象/伴生类:
当在一个文件中,class的名称和object的名称一致的时候,认为class是object的伴生类,object是class的伴生对象
伴生类和伴生对象之间可以互相访问private修饰的变量/属性/方法
apply方法:
object中:
提供了一种便捷的对象构建方式,可以通过object名称以及apply函数的参数列表直接进行对象的构建,不需要使用new关键字
class中:
提供的是一种便捷的数据获取/判断操作,类似list(0)
update方法:
class中:
提供的一种数据插入、更新的便捷操作,类似arr(0) = 100
==============================================
case class:
其实就是class和object的一个结合,内部会自动的生成class对应的object对象,并且在object中产生apply方法
默认的属性是val修饰,可以改为var修饰
注意:case class定义的时候,属性最多22个
最常用的一个地方是:模式匹配
==============================================
trait
当做Java的接口来使用
区别:
1. 可以包含已经实现的方法或者属性
2. 一个类可以继承/实现多个trait
继承:
Scala中的类是单继承的
Trait是可以多继承的
使用关键字extends进行class/trait的继承,多继承的时候使用关键字with
======================================================
泛型
基本和java类型,java使用<>来表示泛型,scala中使用[]来表示泛型
泛型可以出现在:类、object、方法、特质等上面
class Student[T]
def add[T](t:T)
上下界:
[A1 >: A]: 表示A是A1的下界,也就是A是A1的子类
[A1 :< A]: 表示A是A1的上界,也就是A是A1的父类
协变/逆变:
[+T]: 协变, 如果有一个类C定义为C[+T], 同时A是B的子类,那么C[A]也就是C[B]的子类
[-T]:逆变
class Person
class Teacher extends Person
val t:Teacher = new Teacher()
val p:Person = t
class Queue[T]
var q1:Queue[Teacher] = new Queue[Teacher]()
var q2:Queue[Person] = new Queue[Person]()
q1 = q2 // 报错
q2 = q1 // 报错
class Queue[+T]
var q1:Queue[Teacher] = new Queue[Teacher]()
var q2:Queue[Person] = new Queue[Person]()
q1 = q2 // 报错
q2 = q1 // 正常
class Queue[-T]
var q1:Queue[Teacher] = new Queue[Teacher]()
var q2:Queue[Person] = new Queue[Person]()
q1 = q2 // 正常
q2 = q1 // 报错
===================================================