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 // 报错 ===================================================