今天也要加油鸭~
- 这是一份总结的学习笔记
- 路漫漫其修远兮,吾将上下而求索
- 可阅读可评论可分享可转载,希望向优秀的人学习
前言
Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。Scala 运行在Java虚拟机上,并兼容现有的Java程序。java、Scala都是基于JVM的编程语言(文件编译成class文件保存),类相互之间可以调用,Scala并可以调用现有的Java类库;Spark1.6中使用的是Sacla2.10。
- 面向过程:需要你自己去一步一步的执行
- 面向函数:也是需要自己去一步一步执行,只是执行的过程已经提前设定好了
- 面向对象:让机器人去执行 ,因为已经设定好执行步骤,你只需等待结果就好了
总的来说:面向对象是将事物高度抽象化,面向对象必须先建立抽象模型,之后直接使用模型就行了;面向过程是一种自顶向下的编程。
一、Scala官网6个特征
1).Java和scala可以混编(面向对象的其他语言之间类互相调用)
2).类型推测(自动推测类型,不用指定类型,跟JS类似)
3).支持并发和分布式(Actor通信,比如线程与线程之间通信)
4).trait特质,特征(类似java中interfaces 和 abstract结合)
5).模式匹配(类似java中switch case,Scala可以类型/值匹配,java不可类型匹配)
6).高阶函数(不仅返回数值,还能返回函数)
二、Scala安装使用
windows安装,配置环境变量
- 官网下载scala2.10:Scala官网
- 1、下载好后安装。双击msi包安装,记住安装的路径。
- 配置环境变量(和配置jdk一样):
- 新建SCALA_HOME
- 上个步骤完成后,编辑Path变量,在后面追加如下:;%SCALA_HOME%\bin;%SCALA_HOME%\jre\bin(可不加)
- 打开cmd,输入:scala - version 看是否显示版本号,确定是否安装成功
- 1、下载好后安装。双击msi包安装,记住安装的路径。
三、Scala基础
- 知识总结:
类和对象;
定义变量用var,定义常量用val;
类可以传参,有参数就有默认构造
类中的属性有getter,setter方法;
重写构造,第一行先调用默认的构造;
当new classs时,类中除了方法不执行其他都执行;
伴生类和伴生对象。
1、数据类型![数据类型](https://img-blog.csdnimg.cn/20200218170238897.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4OTk1MTU5,size_16,color_FFFFFF,t_70)
![子类父类](https://img-blog.csdnimg.cn/2020021817371611.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4OTk1MTU5,size_16,color_FFFFFF,t_70)
2、变量和常量的声明
基本语法
编译性语言:
/**
1、Scala object 相当于java中的单例,object中定义的是静态的东西
2、定义变量使用var,变量可变。定义常量使用val,常量不可变。会有类型自动推断
3、Scala中一行后面可以不加“;”,有分号自动推断机制,一行语句有多条语句要分号
4、scala类中的属性默认就有getter,setter方法;类可以传参,传参就有了默认的构造。类重写构造,第一行首先调用默认构造。
Scala当new类的时候,除了方法(不包含构造)不执行,其他都执行,方法需要调用
5、伴生类和伴生对象,在一个Scala文件中,如果在同一个文件中,object对象和class类的名称相同,则这个对象就是这个类的伴生对象,这个类就是这个对象的伴生类。可以互相访问私有变量。
**/
class Person(xname:String, xage:Int){
(private) val name = xname
var age = xage
var gender = 'm'
//重写构造
def this(yname:String, yage:Int, ygender:Char){
this(yname, yage)
this.gender = ygender
}
def show() = {
println('score is ' + ClassAndObject.score)
}
}
object ClassAndObject{
val score = 1000
def main(args: Array[string]):unit = {
val a: Double = 100
println(a)
//类和对象
val person = new Person('lisi',19,'f')
person.show()
println(person.name)
println(person.age)
println(person.gender)
}
}
伴生类和伴生对象
class Person(xname :String , xage :Int){
var name = Person.name
val age = xage
var gender = "m"
def this(name:String,age:Int,g:String){
this(name,age)
gender = g
}
def sayName() = {
"my name is "+ name
}
}
object Person {
val name = "zhangsanfeng"
def main(args: Array[String]): Unit = {
val person = new Person("wagnwu",10,"f")
println(person.age);
println(person.sayName())
println(person.gender)
}
}
If else
/**
* if else
*/
val age =18
if (age < 18 ){
println("no allow")
}else if (18<=age&&age<=20){
println("allow with other")
}else{
println("allow self")
}
for循环
println(1 to 10) //range(1,...,10)
println(1 to (10,2)) //range(1,3,5,7,9)
println(1 until 10) //range(1,...,9)
for(i < -1 to 10){
println(i) //1,...,10
}
//多层循环
//可以分号隔开,写入多个list赋值的变量,构成多层for循环
//scala中 不能写count++ count-- 只能写count+
var count = 0;
for(i <- 1 to 10; j <- 1 until 10){
println("i="+ i +", j="+j)
count += 1
}
println(count);
//例子: 打印九九乘法表(双层循环)
for(i <- 1 until 10 ;j <- 1 until 10){
if(i>=j){
print(i +" * " + j + " = "+ i*j+" ")
}
if(i==j ){
println()
}
}
#for循环用yield 关键字返回一个集合
val result = for(i <- 1 to 100;if(i%2==0) if(i>50)) yield i
println(result)
while
var i = 0
while(i < 100){
println("第" + i + "次")
i += 1
#5.scala中不能使用count++,count—只能使用count = count+1 , count += 1
}
Scala函数
object test{
//1、方法的定义
//(1)方法返回值一般省略,若不省略要显示申明方法的返回类型
//(2)方法返回值可以省略,会自动推断,会将方法体最后一行计算的结果作为返回值返回
//(3)如果方法体可以一行搞定,方法的{}可以省略
//(4)定义方法的等号=如果省略,那么无论方法体最后一行计算的结果是什么都会丢弃返回unit(结果会显示括号)
def main(args: Array[String]): Unit ={
def max(x:Int, y:Int) = {
if(x>y) x else y
}
}
}
递归方法
//2.递归方法需要显示的申明方法的返回类型
def fun(x:Int):Int = {
if(a == 1){
1
}else{
a* fun(a-1)
}
}
//3.参数有默认值的方法
def fun(a: Int=100, b:Int=50) = {
a+b
}
println(fun(b=20)) //输出120(100+20)
//4.可变长参数的方法
def fun(ss:String*) = {
for(elem <- ss){
println(elem)
}
//ss.foreach(s=>{
println(s) /***=>是匿名函数,同样是遍历***/
})
//当匿名函数参数只显示一次时可简化 ss.foreach(println(_))参数只有一次的时候,可以简化(_):ss.foreach(println)
fun('q','a','v')
//5.匿名函数: =>
//无参数
val fun = ()=>{
println("hello world")
}
fun()
//有参数
val fun1 = (s:String)=>{
println(s)
}
//6.嵌套方法
def fun(num: Int)= {
def fun1(a: Int){
if(a==1){
a
}else{
a*fun(a-1)
}
}
fun1(num)
}
println(fun(10))
//7.偏应用函数
def showlog(date:Date, log:String) = {
println("date is" + date+",log is" + log)
}
val date1 = new date()
//只有某一个参数变化
val fun = showlog(data1:Date,_:String)
fun("aaa")
//8.高级函数:1)函数的参数是函数;2)函数的返回是函数;3)函数的参数和返回都是函数
def fun(a:Int, b:Int): String = {
a+b+"~"
}
def fun1(f:(Int,Int)=>String,x:Int): String={
val result = f(100,200)
result+"@"+x
}
println(fun1(fun,111)) //'300~@111'
val result = fun1((a:Int,b:Int)=>{
a+"~"+b
},100)
//函数的返回是函数:必须显示申明方法的返回类型是函数
def fun(a:Int, b:Int):(Int,Int)=>Int ={
val result = a+b
def fun1(x:Int, y:Int): Int ={
x+y+result
}
fun1
}
println(fun(1,2)(100,200)) //输出303
//函数的返回和参数是函数
def fun(f:(Int,Int)=>Int):(String,String)=>String={
val result = f(1,2)
def fun1(s1:String, s2:String): String ={
s1+s2+result
}
fun1
}
fun((a:Int,b:Int)=>{a*b})("hello","world")
//9.柯里化函数:高阶函数的简化
def fun(a:Int,b:Int)(c:Int,d:Int) = {
a+b+c+d
}
println(fun(1,2)(3,4))
}
集合
Array:数组
1.创建数组
new ArrayInt
赋值:arr(0) = xxx
ArrayString
2.数组遍历
for
foreach
3.创建一维数组和二维数组
4.数组中方法举例
Array.concate:合并数组
Array.fill(5)(“hello”):创建初始值的定长数组
object Array_test{
def main(args:Array[String]): Unit = {
//合并
val t1 = Array(1,2,3)
val t2 = Array(4,5,6)
val result = Array.concat(t1,t2)
//初始化五个长度为2的数组
Array.fill(5,2)("help")
val arr1 = Array[Int](1,2,3,4)
arr1.foreach(println)
//两种方法
val arr = new Array[Int][3] //指定长度
arr[0] = 100
arr[1] = 200
arr[2] = 300
arr.foreach(println)
}
}
List:跟定义的顺序一致,有序
1.创建list
val list = List(1,2,3,4)
Nil长度为0的list
2.list遍历
foreach ,for
3.list方法举例
filter:过滤元素
count:计算符合条件的元素个数
map:对元素操作
flatmap :压扁扁平,先map再flat
object List_test{
def main(args:Array[String]): Unit = {
val list = List[String]("hello world","hello word","hello wod")
val result = list.map(s=>{
s.split(" ")
})
//将切分分为多个Array,来一条出来一个对象(一对一)
result.foreach(arr=>{
arr.foreach(println)
})
//直接将String返回一个,一对多(先map后flat)
val result2 = list.flatmap(s=>{
s.split(" ")
})
result2.foreach(println)
val result = list.filter(s=>{
s.equals("hello world")
})
}
}
set,无序
1.创建set
注意:set集合会自动去重
2.set遍历
foreach,for
3.set方法举例
交集:intersect ,&
差集: diff ,&~
子集:subsetOf
最大:max
最小:min
转成数组,toList
转成字符串:mkString(“~”)
object set_test{
def main(args:Array[String]): Unit={
val set = Set[Int](1,2,3,4,5)
val set1 = Set[Int](1,2,3,6,7)
val result = set.diff(set1)
result.foreach(println)
}
}
map
1.map创建
Map(1 –>”hell0’)
Map((1,”hello”))
注意:创建map时,相同的key被后面的相同的key顶替掉,只保留一个
2.获取map的值
map.get(“1”).get
map.get(100).getOrElse(“no value”):如果map中没有对应项,赋值为getOrElse传的值。
option:包含some和none
获取所有的values – map.values
3.合并map
++ 例:map1.++(map2) --map1中加入map2
++: 例:map1.++:(map2) –map2中加入map1
注意:合并map会将map中的相同key的value替换
object map_test{
def main(args:Array[String]): Unit={
val map = Map("1"->"a", "2"->"b",("3","c"),("3","cc"))
val result = map.get("3").getOrElse("XXX")
val keys = map.keys
val value = map.values
for(key<- keys){
println("key="+key, "value =" +map.get(key).get )
}
}
}
元组tuple
元组定义:与列表一样,与列表不同的是元组可以包含不同类型的元素。元组的值是通过将单个的值包含在圆括号中构成的。
- 创建元组与取值
val tuple = new Tuple(1) 可以使用new
val tuple2 = Tuple(1,2) 可以不使用new,也可以直接写成val tuple3 =(1,2,3)
取值用”._XX” 可以获取元组中的值
注意:tuple最多支持22个参数 - 元组的遍历
tuple.productlterator得到迭代器,进而遍历
val tuplelterator = tuple22.productlterator
while(tuplelterator.hasnext()){
println(tuplelterator.next())
}
- tuple2 swap交换: swap,toString方法
注意:swap元素翻转,只针对二元组
//翻转,只针对二元组
println(tuple2.swap)
//toString
println(tuple3.toString())
Trait特质特征
- 概念理解
Scala Trait(特征) 相当于java中的抽象类和接口的集合,实际上它比接口还功能强大。
与接口不同的是,它还可以定义属性和方法的实现。
一般情况下Scala的类可以继承多个Trait,从结果来看就是实现了多重继承。Trait(特征) 定义的方式与类类似,但它使用的关键字是 trait。 - 举例:trait中带属性带方法实现
注意:
继承的多个trait中如果有同名的方法和属性,必须要在类中使用“override”重新定义。
trait中不可以传参数,里面可以写方法,方法体,变量,常量 - 类继承多个trait,第一个关键字使用extends,之后使用with
trait read{
val readType = "Read"
val gender = "m"
def read(name:String){
println(name+ "is reading")
}
}
trait Listen{
val listentype = "Listen"
val gender = "m"
def listen(name:String){
println(name+ "is listening")
}
}
//继承多个trait
class Person() extends Read with Listen{
override val gender = "f"
}
object test{
def main(args:Array[String]):Unit = {
val person = new Person()
person.read("wangwu")
person.listen("xiaoming")
}
}
//trait中带方法不实现
trait Equal {
def isEqual(x: Any): Boolean
def isNotEqual(x: Any): Boolean = !isEqual(x)
}
class Point(xc: Int, yc: Int) extends Equal {
var x: Int = xc
var y: Int = yc
def isEqual(obj: Any) =
obj.isInstanceOf[Point] &&
obj.asInstanceOf[Point].x == x
}
object Test {
def main(args: Array[String]) {
val p1 = new Point(2, 3)
val p2 = new Point(2, 4)
val p3 = new Point(3, 3)
println(p1.isNotEqual(p2))
println(p1.isNotEqual(p3))
println(p1.isNotEqual(2))
}
}
模式匹配
- 概念理解:相当于java中的switch …case…
Scala 提供了强大的模式匹配机制,应用也非常广泛;
一个模式匹配包含了一系列备选项,每个都开始于关键字 case;
每个备选项都包含了一个模式及一到多个表达式。箭头符号 => 隔开了模式和表达式。 - 代码及注意点
- 模式匹配(match)不仅可以匹配值还可以匹配类型;
- 从上到下顺序匹配,如果匹配到则不再往下匹配;
- case_=>{…}都匹配不上时,会匹配到case _ ,相当于default,要放到最后;
- match 的最外面的”{ }”可以去掉看成一个语句;
匹配过程中会有数值转化;case s: String=>{…}匹配类型;case 100=>{…}匹配值。
object Test {
def main(args: Array[String]) {
println(matchTest("two")) //2
println(matchTest("test")) //many
println(matchTest(1)) //one
println(matchTest(6)) //scala.Int
}
def matchTest(x: Any): Any = x match {
case 1 => "one"
case "two" => 2
case y: Int => "scala.Int"
case _ => "many"
}
}
case 样例类
- 概念理解
使用了case关键字的类定义就是样例类(case classes),样例类是种特殊的类。实现了类构造参数的getter方法(构造参数默认被声明为val),当构造参数是声明为var类型的,它将帮你实现setter和getter方法。
- 样例类默认帮你实现了toString,equals,copy和hashCode等方法。
- 样例类可以new, 也可以不用new
case class Person1(name:String,age:Int)
object Lesson_CaseClass {
def main(args: Array[String]): Unit = {
val p1 = new Person1("zhangsan",10)
val p2 = Person1("lisi",20)
val p3 = Person1("wangwu",30)
val list = List(p1,p2,p3)
list.foreach { x => {
x match {
case Person1("zhangsan",10) => println("zhangsan")
case Person1("lisi",20) => println("lisi")
case _ => println("no match")
}
} }
Actor
- 概念理解
Actor Model是用来编写并行计算或分布式系统的高层次抽象(类似java中的Thread)让程序员不必为多线程模式下共享锁而烦恼,被用在Erlang 语言上, 高可用性99.9999999 % 一年只有31ms 宕机Actors将状态和行为封装在一个轻量的进程/线程中,但是不和其他Actors分享状态,每个Actors有自己的世界观,当需要和其他Actors交互时,通过发送事件和消息,发送是异步的,非堵塞的(fire-andforget),发送消息后不必等另外Actors回复,也不必暂停,每个Actors有自己的消息队列,进来的消息按先来后到排列,这就有很好的并发策略和可伸缩性,可以建立性能很好的事件驱动系统。
Actor的特征:
- ActorModel是消息传递模型,基本特征就是消息传递
- 消息发送是异步的,非阻塞的
- 消息一旦发送成功,不能修改
- Actor之间传递时,自己决定决定去检查消息,而不是一直等待,是异步非阻塞的(Actor会不定期检查)
什么是Akka
Akka 是一个用 Scala 编写的库,用于简化编写容错的、高可伸缩性的 Java 和Scala 的 Actor 模型应用,底层实现就是Actor,Akka是一个开发库和运行环境,可以用于构建高并发、分布式、可容错、事件驱动的基于JVM的应用。使构建高并发的分布式应用更加容易。
spark1.6之前的底层节点间通信使用的是Akka(多线程框架),Akka是一个通信模型,底层是actor实现,actor也是一个通信模型(类似于java中的多线程编程)。1.6之后使用的netty传输。
Actor发送消息之后,消息不能改变,发送到其他Actor的通信邮箱排队处理,发送消息一端不必等待处理结果结束,可以去执行其他任务
如果当前Actor的请求被处理,会将结果通知到当前Actor的结果邮箱,
- 给Actor发送消息
import scala.actors.Actor
class myActor extends Actor{
def act(){
while(true){
receive{
case x: String => println("get String" + x)
case x: Int =>println("get Int")
case _=> println("get default")
}
}
}
}
object Actor_test{
def main(args:Arrat[String]):Unit = {
//创建actor的消息接受和传递
val actor = new myActor()
//启动
actor.start()
//发送消息写法
actor ! "I love you"
}
}
- Actor和Actor之间发送消息
case class Message(actor:Actor,msg:Any)
class Actor1 extends Actor{
def act(){
while(true){
receive{
case msg :Message => {
println("i sava msg! = "+ msg.msg)
msg.actor!"i love you too !"
}
case msg :String => println(msg)
case _ => println("default msg!")
}
}
}
}
class Actor2(actor :Actor) extends Actor{
actor ! Message(this,"i love you !")
def act(){
while(true){
receive{
case msg :String => {
if(msg.equals("i love you too !")){
println(msg)
actor! "could we have a date !"
}
}
case _ => println("default msg!")
}
}
}
}
object test_Actor2 {
def main(args: Array[String]): Unit = {
val actor1 = new Actor1()
actor1.start()
val actor2 = new Actor2(actor1)
actor2.start()
}
}
四、项目-spark wordcount
重点://用一行实现wordcount
sc.textFile(“路径”).flatMap{.split(" ")}.map{(,1)}.reduceByKey(+).foreach(println)
package com.spark
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.rdd.RDD.rddToPairRDDFunctions
object SparkWordCount{
def main(args:Array[String]):Unit ={
val conf = new SparkConf().setAppName("wordcount").setMaster("local")
val sc = new SparkContext(conf)
val lines: RDD[String] = sc.textFile("./words")
//切分
val words = lines.flatMap(line=>{
line.split(" ")
})
//返回元组
val pairWords:RDD[(String, Int)] = words.map(word=>{
new Tuple2(word,1)
})
//reduceByKey 先分组,再给每个组的value进行聚合
val result:RDD[(String, Int)] = pairWords.reduceBykey((v1,v2)=>{
v1+v2 //第一条和第二条value相加,
})
result.foreach(tuple=>{
println(tuple)
})
//用一行实现wordcount
sc.textFile("./words").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).foreach(println)
//对result的值排序--降序
result.sortBy(tuple=>{tuple._2},flase)
result.foreach(tuple=>{
println(tuple)
})
sc.stop()
}
}