第 1 章 Scala 入门
1.1概述
1.1.1 什么是scala
Scala是一种多范式的编程语言(多范式:多种编程方法的意思。有面向过程、面向对象、泛型、函数式四种程序设计方法),其设计的初衷是要集成面向对象编程和函数式编程的各种特性。Scala运行于Java平台(Java虚拟机),并兼容现有的Java程序
官网:https://www.scala-lang.org/
Scala以一种简洁的高级语言结合了面向对象和函数式编程。 Scala的静态类型有助于避免复杂应用程序中的bug,它的JVM和JavaScript运行时让您能够轻松地构建高性能系统,并轻松访问巨大的库生态系统。
1.1.2我们为什么要学习scala呢?
- 优雅:这是框架设计师第一个要考虑的问题,框架的用户是应用开发程序员,API是否优雅直接影响用户体验。
- 速度快:Scala语言表达能力强,一行代码抵得上Java多行,开发速度快;Scala是静态编译的,所以和JRuby,Groovy比起来速度会快很多。
- 能融合到Hadoop生态圈:Hadoop现在是大数据事实标准,Spark并不是要取代Hadoop,而是要完善Hadoop生态。JVM语言大部分可能会想到Java,但Java做出来的API太丑,或者想实现一个优雅的API太费劲。
- spark分布式运算框架是scala语言编写的
1.1.3scala的发展历史
1.1.4scala和java的关系
正常情况下,会scala的程序员都是会Java的,scala是基于java的,所以我们先搞清楚java,scala和jvm的关系
1.1.5Scala 语言特点
Scala是一门以Java虚拟机(JVM)为运行环境并将面向对象和函数式编程的最佳特性结合在一起的静态类型编程语言(静态语言需要提前编译的如:Java、c、c++等,动态语言如:js)。
- Scala是一门多范式的编程语言,Scala支持面向对象和函数式编程。
- Scala源代码(.scala)会被编译成Java字节码(.class),然后运行于JVM之上,并可以调用现有的Java类库,实现两种语言的无缝对接。
- Scala单作为一门语言来看,非常的简洁高效,可以为我们的代码避免一些bug。
1.2salca环境搭建
由于scala是基于java来开发的, 编写的java类可以使用javac命令编译成.class文件被JVM加载到内存中执行 ! 那么scala可以通过scalac命令将编写的scala文件编译成.class文件一样被JVM加载到内存中,因此Scala是运行在JVM平台上的,所以安装Scala之前要安装JDK!
1.2.1Windows安装Scala编译器
方式一
访问Scala官网http://www.scala-lang.org/下载Scala编译器安装包,目前最新版本是3.1.3,但是目前大多数的框架都是用2.12.x编写开发的,Spark3.x使用的就是2.12.x,所以这里推荐2.12.x版本,下载scala-2.12.11.msi后点击下一步就可以了!
方式二
解压配置系统环境变量
在windows的控制台输入scala ,显示如下消息说明windows环境搞定!
注意 1:解压路径不能有任何中文路径,最好不要有空格。 注意 2:环境变量要大写 SCALA_HOME |
测试:
需求:计算两数 a 和 b 的和。
步骤:
- 在键盘上同时按 win+r 键,并在运行窗口输入 cmd 命令
- 输入 Scala 并按回车键,启动 Scala 环境。然后定义两个变量,并计算求和。
示例:写一个 wordCount
Scala import scala.io.Source
Source.fromFile("C:\\Users\\yi\\Desktop\\wc.txt") .getLines .toList .flatMap(_.split(",")) .groupBy(w=>w) .map(t=>(t._1,t._2.size)) .foreach(println) |
1.2.2Linux安装Scala编译器
- 下载后上传Scala文件到linux上的定目录
- 解压
- 配置环境变量,将scala加入到PATH中
Plaintext vi /etc/profile export SCALA_HOME=/opt/app/scala/scala-2.12.11 export PATH=$PATH:$JAVA_HOME/bin:/usr/java/scala-2.12.11/bin |
测试验证scala安装完成,任意位置输入scala后显示scala的命令行,然后在里面测试两数相加
1.3scala安装插件
方法一:离线安装
打开jetbrains得官网:http://www.jetbrains.com后点击Develop Tools后选择scala
然后选择idea对应得版本下载插件(DownLoad即可)
打开idea后找到左上角得File --》settings --》plugins
点击设置选择Install Plugin from Disk ...后选择刚才下载得插件,点击ok后重启idea即可
方法二:在线安装
打开idea后找到左上角得File --》settings --》plugins--》搜索scala后install后重启idea即可
1.4 创建scala项目并编写HelloWorld案例
- 创建一个maven项目
- 在src--》main--》创建一个scala包
- 右击scala包下选择Mark Directory as --》 Sources Root
- 右击项目名--》Add Framework Support...
- 进去选择scala,然后将scala得sdk添加进去,点击ok即可创建scala类了
编写scala得类
- scala文件都是以.scala结尾的
- scala中的命名规范和java中的一致
- scala中的main方法要写在objec修饰的类中
- scala的执行流程和java的类似 , 先编译再执行,因此有编译期的错误推导
- scala 代码中的行末尾的分号最好不书写 ,体现其简洁
Scala package com.doit.day01 object HelloWorld { def main(args: Array[String]): Unit = { println("学大数据来多易") System.out.println("java中的一部分代码在scala中也是可以运行的") } } |
结果:
第 2 章 scala的基本语法
2.1 注释
对于scala的注释,简而言之就是一句话,和java的注释一模一样
基本语法 (1)单行注释:// (2)多行注释:/* */ (3)文档注释:/** * */ |
代码示例:
Scala package com.doitedu.demo01 object TestNotes { def main(args: Array[String]): Unit = { //(1)单行注释:// println("涛哥") //(2)多行注释:/* */ /* println("涛哥") println("行哥") */ //(3)文档注释: /** * */ /** * println("乃哥") * println("雨哥") * println("行哥") */ } } |
2.2 变量和常量(重点)
Java // 回顾:Java 变量和常量语法 // 变量类型 变量名称 = 初始值 int a = 10 // final 常量类型 常量名称 = 初始值 final int b = 20 |
scala定义变量常量的基本语法
Scala // var 变量名 [: 变量类型] = 初始值 var i:Int = 10 variable :可变的 // val 常量名 [: 常量类型] = 初始值 val j:Int = 20 value :值
var variable 可变的 代表声明变量
val value 值 代表声明常量 |
注意:
- val 在编程的过程中我们大部分的操作是获取值或者是获取一个创建好的对象,然后操作对象中的属性,很少改变这个对象变量
- 优先使用val ,但是当变量后续的需要变化的时候使用var
|
练一练:
- 声明变量时,类型可以省略,编译器自动推导,即类型推导
- 类型确定后,就不能修改,说明 Scala 是强数据类型语言。
- 变量声明时,必须要有初始值
- 在声明/定义一个变量时,可以使用 var 或者 val 来修饰,var 修饰的变量可改变,val修饰的变量不可改。
- var 修饰的对象引用可以改变,val 修饰的对象则不可改变,但对象的状态(值)却是可以改变的。(比如:自定义对象、数组、集合等等)
Scala package com.doitedu.demo02 object TestVar { def main(args: Array[String]): Unit = { //(1)声明变量时,类型可以省略,编译器自动推导,即类型推导 var age = 18 age = 30 //(2)类型确定后,就不能修改,说明 Scala 是强数据类型语言。 // age = "zhangsan" // 错误 //(3)变量声明时,必须要有初始值 // var name //错误 //(4)在声明/定义一个变量时,可以使用 var 或者 val 来修饰,var 修饰的变量可改变,val 修饰的变量不可改。 var num1 = 10 // 可变 val num2 = 20 // 不可变 num1 = 30 // 正确 //num2 = 100 //错误,因为 num2 是 val 修饰的 } } |
Scala object demo03{ def main(args: Array[String]): Unit = { // p1 是 var 修饰的,p1 的属性可以变,而且 p1 本身也可以变 var p1 = new Person() p1.name = "zhangsan" p1 = null // p2 是 val 修饰的,那么 p2 本身就不可变(即 p2 的内存地址不能变), 但是,p2 的属性是可以变,因为属性并没有用 val 修饰。 val p2 = new Person() p2.name="jinlian" // p2 = null // 错误的,因为 p2 是 val 修饰的 } } class Person{ var name : String = "jinlian" } |
练一练:
多易现在开售了一个小课堂来卖课(小型的电商平台): 对于销售这块而言,我们是不是要存在一些属性字段: 店铺名称:多易教育 课程名称:java基础,mysql,hadoop..... 讲课老师:源哥,涛哥,星哥,行哥 课程的价格:199,299,399,99 红包类型: 首次购买红包,老学员红包 红包金额:9.9 18.8 活动名称:老用户再次购买,新用户首次购买,学员推荐购买 活动类型:6.18 10.24 11.11 活动折扣力度:9折 5折 8.8折 购买用户用户名:zhangsan,lisi 用户手机号:18860875775,18860875776 用户现在的职位:etl工程师,大数据开发工程师,数仓工程师 用户的邮箱:email 订单号:111122223333 订单金额:398 |
代码:
Scala package com.doitedu
object demo01{
/** * 店铺名称:多易教育 * 课程名称:java基础,mysql,hadoop..... * 讲课老师:源哥,涛哥,星哥,行哥 * 课程的价格:199,299,399,99 * 红包类型: 首次购买红包,老学员红包 * 红包金额:9.9 18.8 * 活动名称:老用户再次购买,新用户首次购买,学员推荐购买 * 活动类型:6.18 10.24 11.11 * 活动折扣力度:9折 5折 8.8折 * 购买用户用户名:姜海涛,江一 * 用户手机号:18860875775,1886087,5776 * 用户现在的职位:etl工程师,大数据开发工程师,数仓工程师 * 用户的邮箱:email * 订单号:111122223333 * 订单金额:119.4 */ def main(args: Array[String]): Unit = { //店铺名称:多易教育 val shopName = "多易教育" //课程名称:java基础,mysql,hadoop..... val subjectName = "java基础" //讲课老师:源哥,涛哥,星哥,行哥 val tName = "涛哥" //课程的价格:199,299,399,99 val subjectPrice = 199.00 //红包类型: 首次购买红包,老学员红包 val bonusType = "new" //红包金额 val bonus = 9.9 //活动名称 val activeName = "老用户再次购买" //活动类型:6.18 10.24 11.11 val activeType = "程序员节" //活动折扣力度 val activeDiscount = 0.6 //购买用户用户名 val userName = "haiTao Jiang" //用户手机号 val tel = "13372090488" //用户邮箱 val email = "[email protected]" //订单号 val orderId = "111122223333" //订单金额 val orderAmount = 119.4 }
} |
2.3 标识符的命名规范
Scala 对各种变量、方法、函数等命名时使用的字符序列称为标识符。即:凡是自己可 以起名字的地方都叫标识符。 |
命名规则:
Scala 中的标识符声明,基本和 Java 是一致的,但是细节上会有所变化,总结后有三点:
- 以字母或者下划线开头,后接字母、数字、下划线 正常情况下:字母加下划线偶尔来个数字
- 以操作符开头,且只包含操作符(+ - / # !等)
- 用反引号`....`包括的任意字符串,即使是 Scala 关键字(39 个)也可以
• package, import, class, object, trait, extends, with, type, for • private, protected, abstract, sealed, final, implicit, lazy, override • try, catch, finally, throw • if, else, match, case, do, while, for, return, yield • def, val, var • this, super • new • true, false, null |
练一练:
需求:判断 hello、Hello12、1hello、h-b、x h、h_4、_ab、Int、_、+*-/#!、+*-/#!1、if、`if`,这些名字是否合法。
Scala object Test01 { def main(args: Array[String]): Unit = { // (1)以字母或者下划线开头,后接字母、数字、下划线 var hello: String = "" // ok var Hello12: String = "" // ok var 1hello: String = "" // error 数字不能开头 var h-b: String = "" // error 不能用- var x h: String = "" // error 不能有空格 var h_4: String = "" // ok var _ab: String = "" // ok var Int: String = "" // ok 因为在 Scala 中 Int 是预定义的字符,不是关键字,但不推荐 var _: String = "hello" // ok 单独一个下划线不可以作为标识符,因为_被认为是一个方法println(_) //(2)以操作符开头,且只包含操作符(+ - * / # !等) var +*-/#! : String = "" // ok var +*-/#!1 : String = "" // error 以操作符开头,必须都是操作符 //(3)用反引号`....`包括的任意字符串,即使是 Scala 关键字(39 个)也可以 var if : String = "" // error 不能用关键字 var `if` : String = "" // ok 用反引号`....`包括的任意字符串,包括关键字 } } |
2.4 字符串输出
基本语法:
- 字符串,通过+号连接
- printf 用法:字符串,通过%传值。
- 字符串模板(插值字符串):通过$获取变量值
代码测试:
Scala package com.doitedu.demo04 object TestString{ def main(args: Array[String]): Unit = { var name: String = "jinlian" var age: Int = 18 //(1)字符串,通过+号连接 println(name + " " + age) //可以用$来引用变量,大括号{}可以写也可以不写,如果不写,中间要用空格隔开 //最前面小写的s就是固定写法,写了他相当于就是一个模板字符串,咱们可以用$去引用变量了 println(s"${name}今年${age}岁了") //(2)printf 用法字符串,通过%传值。 他是不换行的,如果需要换行,那么要用\r\n来写在末尾换行 printf("name=%s age=%d\r\n",name,age) val price = 119.99 printf("这个商品的价格是%.2f",price)
//(3)字符串,通过$引用 //多行字符串,在 Scala中,利用三个双引号包围多行字符串就可以实现。 //输入的内容,带有空格、\t 之类,导致每一行的开始位置不能整洁对齐。 //应用 scala 的 stripMargin 方法,在 scala 中 stripMargin 默认 是“|”作为连接符,//在多行换行的行头前面加一个“|”符号即可。 val sql = """ |select |name, |count(1) as cnt |from |table_a |where name = "zhangSan" |and age = 18 |group by name; |""".stripMargin println(sql ) //如果需要对变量进行运算,那么可以加${} val sql01 = """ |select |name, |count(1) as cnt |from |table_a |where name = "$name" |and age = ${age+2} |group by name; |""".stripMargin println(sql01 ) val s2 = s"name=$name" println(s2) } } |
printf中格式化输出的模板 %d 十进制数字 %s 字符串 %c 字符 %e 指数浮点数 %f 浮点数 %i 整数(十进制) %o 八进制 %u 无符号十进制 %x 十六进制 |
2.5 数据类型(重点)
Java基本类型:char、byte、short、int、long、float、double、boolean
Java引用类型:(对象类型)
Java基本类型的包装类:Character、Byte、Short、Integer、Long、Float、Double、Boolean
由于Java有基本类型,而且基本类型不是真正意义的对象,即使后面产生了基本类型的包装类,但是仍然存在基本数据类型,所以Java语言并不是真正意思的面向对象。
- scala中的数据类型和java中数据类型最大的区别就是scala中的数据类型都是对象 , 也就是scala中没有原生的数据类型!
- scala中的数据类型分成两类 AnyVal(值类型)和AnyRef(引用类型) , 两种对象都属于Any ,都是对象
val age:Int = 23
age是一个Int数值类型的变量 , 数值类型的变量也属于一个对象 , 所以age变量就是一个对象,也拥有很多方法
注意:Java中基本类型和引用类型没有共同的祖先。
- Any : 所有类型的父类 , 类似于java中的Object
- AnyVal: 数值类型(简单类型) ==-》 对应的是java中的基本数据类型
- AnyRef: 引用数据类型
- Null: 引用类型的子类,类似于java中的null ==》 写了一个类,将null这个值封装在了这个Null里面
- Unit:对应Java中的void,表示方法没有返回值 ,他的值:() ==》 因为针对这个对象,重写了toString 方法
- Nothing: 所类型的子类,主要用在一个函数没有明确返回值时使用,通常异常时使用,表示此处有错
数据类型详细表:
点击图片可查看完整电子表格
Unit 类型、Null 类型和 Nothing 类型
数据类型 |
描述 |
Unit |
表示无值,和其他语言中 void 等同。用作不返回任何结果的方法的结果类型。Unit 只有一个实例值,写成()。 |
Null |
null , Null 类型只有一个实例值 null |
Nothing |
Nothing 类型在 Scala 的类层级最低端;它是任何其他类型的子类型。当一个函数,我们确定没有正常的返回值,可以用 Nothing 来指定返回类型,这样有一个好处,就是我们可以把返回的值(异常)赋给其它的函数或者变量(兼容性) |
2.6 类型转换
当Scala 程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数值类型,这
个就是自动类型转换(隐式转换)。数据类型按精度(容量)大小排序为:
说明:
- 自动提升原则:有多种类型的数据混合运算时,系统首先自动将所有数据转换成精度大的那种数据类型,然后再进行计算。
- 把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动类型转换。toInt toDouble
- (byte,short)和 char 之间不会相互自动转换。
- byte,short,char 他们三者可以计算,在计算时首先转换为 int 类型。
测试案例:
Scala object Test { def main(args: Array[String]): Unit = { //(1)自动提升原则:有多种类型的数据混合运算时,系统首先自动将所有数据转换成精度大的那种数值类型,然后再进行计算。 var n = 1 + 2.0 println(n) // n 就是 Double //(2)把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动类型转换。 var n2 : Double= 1.0 //var n3 : Int = n2 //错误,原因不能把高精度的数据直接赋值和低精度。 //(3)(byte,short)和 char 之间不会相互自动转换。 var n4 : Byte = 1 //var c1 : Char = n4 //错误 var n5:Int = n4 //(4)byte,short,char 他们三者可以计算,在计算时首先转换为 int类型。 var n6 : Byte = 1 var c2 : Char = 1 // var n : Short = n6 + c2 //当 n6 + c2 结果类型就是 int // var n7 : Short = 10 + 90 //错误 } } |
第 3 章 运算符 基本和java一样
3.1算术运算符
测试代码:
Scala object Test { def main(args: Array[String]) { var a = 10; var b = 20; var c = 25; var d = 25; println("a + b = " + (a + b) ); println("a - b = " + (a - b) ); println("a * b = " + (a * b) ); println("b / a = " + (b / a) ); println("b % a = " + (b % a) ); println("c % a = " + (c % a) ); } } |
3.2关系运算符
点击图片可查看完整电子表格
代码测试:
Scala def main(args: Array[String]) { var a = 10; var b = 20; println("a == b = " + (a == b) ); println("a != b = " + (a != b) ); println("a > b = " + (a > b) ); println("a < b = " + (a < b) ); println("b >= a = " + (b >= a) ); println("b <= a = " + (b <= a) ); } |
3.3逻辑运算符
点击图片可查看完整电子表格
代码测试:
Scala val a = true val b = false
println("a && b = " + (a && b))//false
println("a || b = " + (a || b))//true
println("!(a && b) = " + !(a && b))//true |
3.4赋值运算符
注意:scala中是没有++ -- 替换 += -=
点击图片可查看完整电子表格
代码测试:
Scala object Test { def main(args: Array[String]): Unit = { var r1 = 10 r1 += 1 // 没有++ r1 -= 2 // 没有-- } } |
3.5 位运算符
测试代码:
Scala object TestPosition { def main(args: Array[String]): Unit = { // 测试:1000 << 1 =>10000 var n1 :Int =8 n1 = n1 << 1 println(n1) //16 } } |
3.6优先级
由于Scala是由JAVA 写的编程 , 运行于JAVA的平台( java虚拟机) 中 所以运行的速度比JAVA慢 .
Scala有许多的地方和Java一样 , 但是我看更有点像是Python 和 Java结合 .
学习Java的掌握程度大大的影响着Scala的学习进度 , 这前面的章节很多都学习过 温故知新 .