Spark学习笔记[1]-scala环境安装与基本语法

  正所谓工欲善其事必先利其器,Spark的开发语言不是java而是scala,虽然都是运行于JVM,但是两门语言的基本特性还是有些不一样,这里说明一个概念,JVM不等于JAVA,任何语言只要能编译出符合JVM规范的class文件,都可以运行在JVM上

  相比于java,scala语言更加简简洁,且其实函数式编程语言,函数式变成语言的含义就是任何函数都是变量,有点类似于C++中的函数指针,由于语法很简洁,所以带来的问题就是相比于Java,用scala写的代码的代码可读性会差那么一点点

  变成语言说到底都只是一门工具,语言特性有差异,但是其能支持的功能基本上都大同小异,本文着重介绍一些scala语言的基本特性,详细的内容可以直接查看官网

1、准备工作(以windows系统为例)

  • 1)、从官网下载scala的安装包,https://www.scala-lang.org/download/2.12.1.html , windows系统下载对应的msi文件,双击安装即可,安装过程中不能安装在默认的文件夹,默认文件夹是Program Files (x86),路径带空格,会报错

  • 2)、添加环境变量,也可以在安装时由程序写入path

  • 3)、打开命令行输入scala,如果能进入scala的编辑界面,则说明安装完成

  • 4)、本文采用的集成开发工具是IDEA,scal可以集成到IDEA需要先安装scala的插件,具体可以参考博客:https://blog.csdn.net/zhujq_icode/article/details/82501559

2、基本语法及语言特性

2-1 main、class、 object和语句书写规则介绍
  • Java的类定义关键字是class,scala除了class外还有object关键字,主方法(main)主方法只能写在object定义的类中,示例代码如下:
object Collection {def main(args: Array[String]): Unit = {}
}
  • Java的一个文件只能由一个主类,且主类名字和文件名必须一致,scala没有这个要求
  • **object和class的区别:**scala中使用class定义类时不可有静态变量和静态方法(根本就没有static关键字),scala中static的功能可以用object类来实现(所以main必须在object中),但是该object类和class类必须定义在一个文件中,且必须同名,此时这个Object被称为"伴侣对象",例如同一个文件中的class A和Object A就是伴生对象,A中的变量就是class A的静态属性
  • Object定义的类相当于静态的单例对象
  • 在Java中以分号标志一行语句,scala中分号可有可无,但是同一行如果有多句,需要用逗号分隔
  • 虽然scala允许文件名和类名不一致且一个文件可以有多个类,但是scala最终也需要编译成符合JVM规范的class文件,所以最终会由scala编译器生成类名和文件名一致的class类,所以同一个包下的不同文件不允许存在名称相同的类
  • 在scala中类体中可以执行业务逻辑,在Java中业务逻辑只能在方法中执行,在scala中定义在类体中的业务逻辑【也就是裸露的代码】会被scala编译器编译到默认构造函数,比如如下定义在类中裸露代码
class test{var a:Int = 3val name = "bbb"println(s"test.......$a")println(s"test......${a+1}")}
2-2 变量定义
var/val 变量名:类型 = 值  //var定义变量,val定义常量,var定义的变量可以改值,val类似于final
2-3 构造函数

  scala中的可以写构造函数,如果不写,默认的构造函数就是由类体中的裸露代码构成,如果定义了个性化构造函数,定义方式如下

def this(参数名称:参数类型.....){//必须调用默认构造函数this()}
2-4 类名构造器

  除了常规的构造器,scala还有类名构造器,类名构造器的定义方式如下

 class A(var/val name[名称]:String[类型]){}new A(name="aaa")

类名构造器的基本特点如下:

  • 1)、var/val可以省略,默认是val且为private
  • 2)、只有在类名构造器中的参数可以设置为var,其余方法中的参数都是val类型,且不允许设置成var类型
  • 3)、如果有类名构造器,又定义了自定义构造器,则在自定义构造器中调用默认构造器需要显示对其进行初始化,例如将A改成
calss A(name:String){def this(age:Int){this("aaa") //显示初始化类名构造器中的参数}}
2-5 流程控制
2-5-1 if/else

和java一样

 var i:Int = 0;
if(i == 0){println("i=0")
}else{println("aaaa")
}
2-5-2 while循环

和java一样,但是没有++这种自增的语法,直接用+=1替代

 var i = 0while(i<10){println(i)i +=1}
2-5-3 for循环

scala不支持for(int i=0;i<10;i++)这种语法,只支持增强的for循环,类似于java 中就是for(a:迭代器, 使用scala实现for(int i=0;i<10;i++)的语法是:

 for(i <- 0 to (9,1)){ //包含9println(i)}for(j <- 0 until (10,1)){//不包含10println(j)}

循环表达式后面可以跟判断条件,例如满足某一个条件才执行循环体

 for(i <- 0 to (9,1) if (i%2==0)){println(i)}

双层for循环直接使用更加简洁,例如打印乘法表

  for(i <- 1 to 9 /*外层循环*/;j <- 1 to 9 if (i >= j) /*内层循环*/){print(s"$j * $i = ${i*j} \t")if(i==j){println("")}
2-6 函数
2-6-1 常规函数

函数定义

      def 函数名(形参列表【都是形参名称:形参类型的格式】):返回值类型 = {}

如果函数无返回值,则返回值类型是Unit,函数的返回值类型可以用return,也可以直接将变量写在最后一行即可,例如

     def test1(): Int ={var i = 3//return ii}

如果函数无返回值,则返回值类型是Unit,函数的返回值类型可以用return,也可以直接将变量写在最后一行即可,例如

2-6-2 匿名函数
      var y= (形参列表) =>{函数体}//或者var y:(Int,Int)=>Int = (a:Int,b:Int)=>{a+b}

y:(Int,Int)=>Int叫函数的签名,可以作为函数的形参存在,调用匿名函数和调用普通函数差不多,就是y(形参)

2-6-3 嵌套函数(函数中定义函数)
 def test1(a:String):Unit = {def test2():Unit = {println(a)}test2()}test1("hello")
2-6-4 偏应用函数
        def fun07(date:Date,tp:String,msg:String): Unit ={println(s"$date\t$tp\t$msg")}var info = fun07(_:Date,"info","ok") //固定了后面两个参数,第一个参数"_"是占位info(new Date())
2-6-5 可变参数函数
 def fun08(a: Int*): Unit = {for (elem <- a) {println(elem)}//函数作为参数a.foreach(println) //打印a的每一个原数,foreach接收一个形参的函数,返回值是泛型,println只有一个形参,返回值为Unit}fun08(8)
println("-------------")
fun08(1,2,3,4)
2-6-6 高阶函数

函数作为参数或者返回值

       //函数作为参数,y:(Int,Int)=>Int就是所需函数格式,接收两个参数,返回一个Int数据def compute(a:Int,b:Int,y:(Int,Int)=>Int):Int = {y(a,b)}println(compute(3,4,(a:Int,b:Int)=>{a+b}))println(compute(3,4,(a:Int,b:Int)=>{a*b}))println(compute(3,4,_ % _))println("--------------------------------")//函数作为返回值def factory(op:String):(Int,Int)=>Int ={if(op.equals("+")){(a:Int,b:Int)=>{a+b}}else{(a:Int,b:Int)=>{a*b}}}var addFunc = factory("+")var mulFunc = factory("*")println(addFunc(3,4))println(mulFunc(3,4))
2-6-7 柯理化

又称为多参数列表,感觉有点抽象,形式如下

      def func09(a:Int)(b:String): Unit = {println(s"$a\t$b")}func09(5)("hello")

是不是感觉很多余,直接定义def func09(a:Int,b:String)不就好了,主要用途

  • 1)、用于接收可变参数列表类型不一致时使用
def func09(a:Int*)(b:String*): Unit = {//      println(s"$a\t$b")a.foreach(println)b.foreach(println)}func09(5,6)("hello","word")
// 当然可以用 def func09(a:Any*)实现,但是此时就无法控制传入的参数类型
  • 2)、**隐式参数:**如果要指定参数列表中的某些参数为隐式(implicit),应该使用多参数列表
2-7 集合框架
  • 1)、 使用java的集合框架,虽然是java写的,但是已经编译成字节码,都是运行在JVM上,所以scala可以使用java的类库

  • <font size=4.5 face='楷体’21)、 scala自己定义的集合类,有两大类,可变(mutable)和不可变(immutable),默认使用的是不可变包中的集合类,例子如下

       //数组var arr01 = Array(1,2,3,4)println(arr01(0)) //用小括号取对应索引,[]在scala是泛型参数var arr02 = Array[Int](1,2,3,4)//链表var list01 = List(1,2,3,4,5) //不可变Listlist01.foreach(println)//可变Listvar list02 = new ListBuffer[Int]()list02.+=(32) //添加元素,++ ++:等操作符的含义见https://blog.csdn.net/z1941563559/article/details/88751099//集合set //可变和不可变//元组var t2 = new Tuple2(11,"sssss") //2 代表可以有2个元素,最多可以Tuple22println(t2._1) //取值//迭代val iterator = t2.productIterator //拿到迭代器iterator.foreach(println)//Tuple2在scala描述的就是键值对mapimport scala.collection.mutable.Mapval map01:Map[String,Int] = Map(("a", 33), "b" -> 22, ("c", "44"))val keys:Iterable[String] = map01.keysmap01.put("d",444)val value = map01.get("a").getOrElse("aa")// get("a")返回的是Option类型,Option内部有两个值,none和some,有值就是返回some,没有值返回none,再通过一层取到值//集合操作//map方法,接收一个函数,一进一出val list = List(1,2,3,4,5)val list02 = list.map((x: Int) => (x * x))list02.foreach(println)//reduce方法,接收一个函数,多进一出list.reduce((a:Int,b:Int)=>(a+b)) //内部调用的是reduceLeft,从左到右累加,初始值是0//flatMap方法,集合展开val list03 = List("hello word","hello jeje")val strings = list03.flatMap((x: String) => {x.split(" ")})strings.foreach(println)
2-8 迭代器

为了避免一次将大量数据直接加载到内存导致内存溢出,数据计算领域大量使用了迭代器模式,只需要保存指向真实数据的指针,通过对指针的迭代迭代数据,举个例子说明一下使用迭代器迭代scala的列表

        val list03 = List("hello word","hello jeje","hehe hhhhhh")val iter:Iterator[String] = list03.iteratorval strings = iter.flatMap((x: String) => {x.split(" ")}) //返回的也是迭代器,没有发生实际的计算//    strings.foreach(println) //迭代元素,发生计算,最终调用的是iter的next和hasnext方法,可以看下源码val tuples = strings.map((_, 1))//strings是迭代器,且已经在调用strings.foreach后指向末尾,再对其进行map迭代,已经无法输出元素tuples.foreach(println)
2-9 高级特性
2-9-1 trait

类似于接口【编译后确实是接口】,用于多继承

         trait A {def say(): Unit={println("1")}}trait B {def sayB():Unit={println("2")}def sayB2():Unit}class Person(name:String) extends A with B {def hello(): Unit = {println(s"$name say hello")}override def sayB2(): Unit ={println("3")}}object traitTest {def main(args: Array[String]): Unit = {val p = new Person("ssss")p.sayB2()}}
2-9-2 case class

样例类,主要用于模式匹配,和普通类不一样的是样例类的比较是比较值而不是引用,所以如下的a和a2是相等的

         //类似于工厂,只要构造实例的值一样,出厂的产品就相同case class Dog(name:String,age:Int){}object caseClassTest {def main(args: Array[String]): Unit = {val a = new Dog("hashiqi", 18)val a2 = new Dog("hashiqi", 18)println(a.equals(a2))}
2-9-3 match 模式匹配

感觉上像是一个增强的switch,不仅可以对值进行匹配,还能对类型进行匹配

         val tup:(Double,Int,String,Char) = (1.0, 2, "aaa", 'a')val iter = tup.productIteratorval res = iter.map((x:Any)=>{x match{case 1.0 => println("1.0")  //匹配值//        case 2 => println("2")case o:Int => println(s"$o is Int") //匹配类型,o就是传入的xcase o:String => println(s"$o is String")case _ => println("default") //默认情况,也就是switch的default规则}})while(res.hasNext){res.next()}
2-10 偏函数

根据对应的规则处理数据返回对应值

         //第一个位置是传入参数,第二个参数是返回值类型def test:PartialFunction[Any,String]={case "hello" => "val is Hello"case x:Int => s"$x is Int"case _ => "none"}println(test(44))println(test("hello"))println(test('a'))
2-11 隐式转换

隐式转换的作用是对现有的已经编译好的类进行增强,假设现在使用的是java的LinkList

             val list01 = new util.LinkedList[Int]()list01.add(1)list01.add(2)list01.add(3)

需要对其进行遍历,但是java的LinkList没有foreach方法,可以通过以下方法对其进行包装

  • 1)、 封装方法
   def foreach[T](linkedList: util.LinkedList[T],f:(T)=>Unit)={ //T是泛型参数val iter = linkedList.iterator()while(iter.hasNext){f(iter.next())}}foreach(list01,println)
  • 2)、 封装类
class ListEx[T](linkedList: util.LinkedList[T]){def foreach(f:(T)=>Unit)={val iter = linkedList.iterator()while(iter.hasNext){f(iter.next())}}}//    用类封装val listex = new ListEx(list01)listex.foreach(println)
  • 3)、 同样使用类对其封装,使用隐式转换方法对原有集合进行增强
//隐式转换方法,名称无所谓,类型要对implicit def tran[T](linkedList: util.LinkedList[T]):Unit={new ListEx(linkedList)}list01.forEach(println)
  • 4)、 使用隐式转换类
implicit class tran[T](linkedList: util.LinkedList[T]) {def foreach(f: (T) => Unit) = {val iter = linkedList.iterator()while (iter.hasNext) {f(iter.next())}}}list01.forEach(println)

使用隐式转换可以在不修改源码的情况下对类功能进行增强,除了隐式转换函数和类,还有隐式转换参数,如下

implicit val aa:String = "aaa"
def aaaa(implicit aaa:String):Unit={ //代表参数可传可不传,不传的话,会从程序中定义的implicit变量寻找类型相匹配的填入,如寻找到多个则报错println(aaa)}//调用方式aaaa("bbb")aaaa//如果此时函数改成def aaaa(implicit aaa:String,bbb:Int)//虽然有一个String类型的隐式变量,但是调用aaaa时也不能只穿bbb参数,必须同时传入或者不传,若想实现只传入bbb的功能,需要用到柯理化(多参数列表),将函数定义成def test01(bbb:Int)(implicit aaa:String):Unit ={println(s"$aaa ----> $bbb")}test01(10)

Spark学习笔记[1]-scala环境安装与基本语法相关推荐

  1. 安装成功配置环境变量_go语言学习笔记-Windows10开发环境安装和环境变量配置

    相关文档 go语言学习笔记-目录 1.安装 1.1.访问 https://golang.google.cn/dl/ 或 https://golang.org/dl/ 下载官方安装包 1.2.选择Win ...

  2. dataframe scala 修改值_【Spark学习笔记】 Scala DataFrame操作大全

    1.创建DataFrame 本文所使用的DataFrame是通过读取mysql数据库获得的,代码如下: val spark = SparkSession .builder() .appName(&qu ...

  3. Spark学习笔记09:Scala类和对象

    目录 一.类 (一)类的定义 (二)类的实例化 二.单例对象 (一)单例对象概念 (二)案例演示 三.伴生对象 (一)伴生对象概念 (二)案例演示 四.get和set方法 (一)生成原则 1.val修 ...

  4. SQL学习笔记——task1:数据库安装及基本语法操作

    文章目录 前言 一.MySQL 8.0的下载与安装 1.1Windows下MySQL8.0的下载安装 二.数据库知识点 2.1初始数据库 2.2 初始SQL 3.数据库的创建 前言 一.MySQL 8 ...

  5. Spark学习笔记1——第一个Spark程序:单词数统计

    Spark学习笔记1--第一个Spark程序:单词数统计 笔记摘抄自 [美] Holden Karau 等著的<Spark快速大数据分析> 添加依赖 通过 Maven 添加 Spark-c ...

  6. Clojure学习笔记(一)——介绍、安装和语法

    Clojure学习笔记(一)--介绍.安装和语法 什么是Clojure Clojure是一种动态的.强类型的.寄居在JVM上的语言. Clojure的特性: 函数式编程基础,包括一套性能可以和典型可变 ...

  7. python3.4学习笔记(十八) pycharm 安装使用、注册码、显示行号和字体大小等常用设置...

    python3.4学习笔记(十八) pycharm 安装使用.注册码.显示行号和字体大小等常用设置 Download JetBrains Python IDE :: PyCharm http://ww ...

  8. Ionic 学习笔记之-痛彻心扉的环境搭建

    Ionic 学习笔记之-痛彻心扉的环境搭建 最近在学习Ionic 做多平台的应用.跨平台应用.就是用html写的界面.js实现逻辑. 在学ionic之前选了各种跨平台APP开发框架.最后选择了ioni ...

  9. OpenGL学习笔记(一):环境搭建、三维空间坐标系理解以及OpenGL的基本使用

    原博主博客地址:http://blog.csdn.net/qq21497936 本文章博客地址:http://blog.csdn.net/qq21497936/article/details/7866 ...

最新文章

  1. python 模拟键盘_Python 模拟键盘输入 | 学步园
  2. Google Protocol Buffer 简单介绍
  3. php yof框架特点_腾讯正式开源高性能超轻量级 PHP 框架 Biny
  4. 【C 语言】指针间接赋值 ( 指针作为 函数参数 的意义 | 间接赋值 代码示例 )
  5. spark on yarn任务提交及运行完整流程图
  6. 深度学习和目标检测系列教程 21-300:deepsorts测试小车经过的时间和速度
  7. mysql 视图 字典_MySQL深入01-SQL语言-数据字典-服务器变量-数据操作DML-视图
  8. 远程桌面连接_Win10 系统远程桌面连接怎么打开
  9. ubuntu下创建定时任务的两种方式及常见问题解决方案
  10. ajax取消重复请求
  11. mysql 图像数据类型_MySQL数据类型
  12. python中的字体英文名,CSS 中文字体的英文名称
  13. python读取xps文件_Python操做PDF-文本和图片提取(使用PyPDF2和PyMuPDF)
  14. 表格票据识别人工智能OCR
  15. 常用安防软件,Onvif,RSTP客户端 , 小工具
  16. PCAN-View如何保存报文?
  17. Tuxera NTFS2022产品密钥 mac读取ntfs格式驱动程序
  18. 如何留住你的员工——员工流失分析
  19. Tomcat+Nginx动静分离
  20. 在V2EX的开发环境里尝试了一下OneAPM @livid

热门文章

  1. C# 使用System.Drawing.Bitmap报错
  2. 真正的成功,是一群人一起成事
  3. 小程序开发+weuiwxss
  4. PIXI学习历程 -- 持续更新
  5. vs2010 sp 1 下载
  6. markdown mermaid
  7. 组件 :normal ordered local Broadcasts
  8. 环保材料营造健康氛围
  9. shell脚本之sed开发
  10. 【Python】采集3万张4K超清壁纸,实现定时自动更换桌面壁纸脚本(内含完整源码)