Spark、Kafka等相关大数据技术框架底层都是由Scala编程语言编写的,Spark我们自己编写分布式程序时,Spark提供了多种编程语言风格,但是我们比较常用的是使用Scala编程。
Scala是一门多范式编程语法,所谓多范式指的就是多种编程风格的语法,Scala主要是一门面向对象编程语言和函数式编程语言。
Scala的发明人是马丁奥德斯基,Scala语言2001年左右诞生的,融合了Java和JS中很多特性。
同时Java中很多特性也是从Scala语言中吸收到,JDK8.0版本拉姆达表达式就是从Scala中吸收到
Java中函数编程式接口、拉姆达表达式、方法引用 接口的组成、时间日期类、Stream API、Optional类(解决NullPonitException的)
Java中的拉姆达(λ)表达式是和Java中的一个接口紧密相关的,接口函数式编程接口(接口中只有一个抽象方法)
语法:(形参列表)-> {方法体;}
package lambda;
import java.io.PrintStream;
public class Demo {
public static void test(Flyable flyable){
flyable.fly("zs");
}
public static void test1(A a){
}
/**
* 使用函数式编程接口时,如果我们采用匿名内部类的形式,必须要去重写唯一的抽象方法,而且匿名内部类最核心的也是抽象方法
* 所以此时我们就是使用拉姆达表达式将匿名内部类的代码给简化了即可
*
* (形参列表) -> {方法体} 就是抽象方法的简化
* @param args
*/
public static void main(String[] args) {
test(System.out::println);
test(name-> System.out.println(name));
}
}
interface A{
default void run(String name){}
default int call(){return 0;}
}
package lambda;
@FunctionalInterface
public interface Flyable {
void fly(String name);
static int run(){ return 0;}
}
拉姆达表达式的简化:
Java中的方法引用相当于是拉姆达表达式的升级版本,主要就是用来替换整个拉姆达表达式的,当拉姆达表达式的方法体是引用了另外一个类的方法,并且方法体中没有多余的代码时,可以使用方法引用来简化代码
Scanner
StdIn.readxxx()
System.out.xxx
print()/println()
print/println(s"xxxxx$变量名")
print/println("xxxxx%s %d",变量,变量)
语法: var|val 变量名|常量名【:数据类型】 = 初始值;
【注意】虽然Scala中数据类型可以省略,但是Scala是一门强类型编程语法
Scala是一门纯面向对象的编程语言,因此在Scala中所有的数据类型都是对象
Scala中所有类型的顶尖父类:Any,Any有两个直接子类:AnyVal、AnyRef
AnyVal是值类型:Byte、Short、Int、Long、Float、Double、Char、Boolean、Unit
AnyRef是引用类型:Java中所有类、Scala中所有类、Scala中所有集合、Null
Unit、Null、Nothing三个比较特殊的类型
没有++ –
+= -=…
Scala中==代表比较值相等,比较地址相等用eq函数
【注意】Scala运算符本质上是一个函数,函数的名字是数学符号,正常情况下运算符的使用语法应该如下: 1 + 1 1.+(1)
函数调用的时候可以简化:
- 函数调用的点可以省略的
- 如果函数的参数只有一个,那么()可以省略的
顺序流程:代码遵循从上而下依次执行
if类型的分支:Java一模一样的
模式匹配
语法:
x match{
case 值|x [模式守卫if] => case分支语句
case 值|x [模式守卫if] => case分支语句
case _ => case分支语句
}
【模式守卫】模式守卫可以做范围匹配,一般使用模式守卫时,case需要x
for循环
until型的for循环:
for(i <- start until end)
to型的for循环:
for(i <- start to end)
增强的for循环——遍历集合或者数组:
for(elem <- 集合/数组的变量)
for循环的步长(迭代,默认情况下迭代+1):
for(i <- start until|to end by num)
循环守卫(满足某个条件再执行循环体):
for(i <- start until|to end 【by num】 if 语句)
多重循环:
for(i <- start until|to end by num 循环守卫 ;j<- start until|to end by num 循环守卫)
循环的返回值问题(将循环的值赋予给一个Scala集合):
var array = for(i <- start until|to end by num 循环守卫) yield i
while循环
do while循环
2~3:和Java语法是一模一样的
def 函数名(形参列表):函数的返回值类型={ 函数体 }
可变长形参 参数名:数据类型*
,一个函数只能有一个可变长形参,而且形参必须位于函数形参列表的末尾
形参的默认值,Scala函数当中,形参是可以赋予默认值的,一旦形参赋予默认值,那么调用参数的时候,带有默认值的形参就可以不用传递参数了,带有默认值的形参一般要求放到形参列表的最后,如果没有放到最后,那么调用的时候,给其他形参传递参数,需要带有参数名传递
def test(name:String=zs,age:int){}
test(age=1)--具名实参
【注意】函数有两种特殊的返回值:Unit、Nothing
【注】在Scala中,函数是一等公民,函数可以在Scala的任何位置充当任何的角色,函数可以声明在类中,也可以声明在函数中,还可以声明在参数列表中、还可以当作返回值,还可以当作一个变量
var d:函数的定义 = 函数名 _
【注意】函数的类型如何声明: (形参类型列表) => 返回值类型
示例:
函数的定义:
def test(a:Int,b:Int):Int={a+b}
函数的类型写法:
(Int,Int) => Int
语法:
def test(a:Int,f:(Int,Int)=>Int):Unit={ }
语法:
def test():(Int,Int)=>Int={ }
4.4.2~4.4.3 :Scala中存在匿名函数,专门使用在这两个场景
函数闭包指的是将不属于本函数的变量或者对象也包含进来,直到该函数运行完成,外部变量或者对象才可以被释放。
var x:Int = 1 def test(a:Int):Int={ a*x }
将一个接受多个参数的函数给他转换成为一个接受单个参数的函数的过程
将一个接受多个参数的函数转换成为一个返回了函数的函数,返回的函数传递的值就是原先的第二个参数
其实闭包的一个使用场景
函数内部调用本函数
递归三要素
惰性加载指的是将函数的调用延迟到第一次使用函数的返回值的时候才会调用
使用语法: lazy val 变量名 = 函数名(实参)
此时函数的调用在第一次使用变量的时候才会调用 一旦惰性加载,变量名只能使用val修饰
如果函数没有参数,那么函数的括号可以省略 def test:Unit={}
函数的返回值可以省略的,可以根据函数体的最后一行自动推断,
【注意】如果函数体的最后一行使用return 关键字返回数据,那么函数的返回值一定不能省略的
def test = { 1 }
函数体中,函数的返回值前的return关键字可以省略的,自动根据最后一行推断函数的返回值
如果函数的返回值类型是 Unit类型 那么 =号和函数 的返回值都可以省略 def test{}
匿名函数
(形参列表) => {函数体}
调用的语法:对象名|类名.函数名(实参列表)
对象名|类名 函数名(实参列表)
对象名|类名 函数名 唯一的实参
Scala源于Java中,因此在Scala中也存在面向对象编程思想,面向对象编程最核心的逻辑就是以类来组织代码,以对象来调用代码。Scala的面向对象和Java基本上思维是一致的,只不过就是语法稍微不一样而已。
包package:包是用来分类管理Scala代码的,将不同类型的代码放到不同的包下,便于我们管理
采用和Java一样的管理机制,新建包,包下可以新建类和子包
采用包对象的管理机制,实现一个文件中存在多个包和多个scala类
在当前Scala类中,如果要使用非本包下的代码,那么我们就得需要通过import关键字导入才能使用。
每一个Scala类默认导入三个包
java.lang.
_scala._
scala.Predef._
Scala类中导入有一些规则和Java有点不一样
Scala可以在任何位置进行导包操作,代码只能在导包位置之后使用 我们可以把所有的包放到package之后 class之前
如果我们要导入一个包下的所有代码,那么可以使用_当作通配符使用
我们现在只想导入某一个包下的两个类,而非所有类 import xxxx.{x1,x2}
导包重命名操作:可以将一个类重命名为另外一个名字在当前类中使用
import xxxx.{x1=>x2}
x1类在当前类中可以使用x2名字来替代
屏蔽某一个包下的部分类:导入一个包下的所有代码,除了某几个类之外
import xxxx{x1=>_,x2}
导入xxxx包下的x2类,不导入x1这个类
访问控制修饰符 class 类名(主构造器){ 类体 }
三个 private protected public–不写
在同一个Scala文件中可以存在多个Scala类,权限没要求的
属性用来描述类的特征
访问控制修饰符 var|val 属性名:属性类型 = 值;
属性声明的时候必须加值,但是我不想给其他值,只想给默认值,那么值使用**_** 来代替
【注意】
val修饰的属性 不能赋予 _ 默认值,必须给一个显示的值
属性前加一个注解
@BeanProperty
方法就是函数,函数声明在类中,函数称之为方法
访问控制修饰符 def 方法名(形参列表):方法的返回值类型 ={ 方法体 }
{} 类中类
class ClassName 访问控制修饰符 (形参列表)--主构造器
def this(形参列表){ }
【注意】
主构造器不存在构造体,那么也就意味着主构造器无法给属性赋值,为了可以给属性赋值,主构造器的形参列表有个变化,主构造器的形参列表可以使用var或者val修饰,一旦主构造器的形参使用var val修饰 那么主构造器中的形参就是类的属性了
主构造器我们一般都是要求是无参构造器,而且主构造器一旦是无参的,那么主构造器的()可以省却