一, Scala基础语法全总结
文章目录
一, 简单入门
1.1 为什么要学习Scala?
-
Java的扩展和延伸
- Scala基于JVM, 和Java完全兼容, 同样具有跨平台,可以执行好,方便的垃圾回收等特性;
- Scala是一种纯粹的面向对象语言;
- Scala是一门函数式编程语言;
-
Scala更适合大数据的处理
- Scala对集合类型数据处理有非常好的支持
- Spark的底层用Scla编写, 深入学习Spark必定要掌握Scala
1.2 Scala 与 Java, JVM的关系
1.3 Scala语言的特点
1.4 Scala 安装和IDE的配置
1.5 HelloWorld 案例
object HelloWorld{
//定义方法 main == def 方法名(参数名: 参数类型):返回值 ={}
def mian(args: Array[String]): unit={
println("Hello World!!")
}
}
1.6 对反编译Scala字节码文件的解读
待补充
1.7 Scala 中的 Object和Class
待补充
二, 变量和数据类型
2.1 注释
Scala的注释使用和Java 完全相同
// 1.单行注释
/* */ 2. 多行注释
/** 3. 文档注释
*
**/
2.2 Scala 的变量和常量
常量: 在程序执行的过程中, 值不会改变的变量
- Java中的变量和常量语法
- 变量类型 变量名 = 值, int a = 10;
- final 常量类型 常量名 = 值, final int b = 20;
- Scala中的变量和常量
变量写法 | 实例 |
---|---|
var 变量名 [: 变量类型] = 初始值 | var i:Int = 10 |
常量写法 | 实例 |
---|---|
val 常量名 [:常量类型] = 初始值 | var j:Int = 20 |
注意:
- 声明变量时, 类型可以忽略, 编译器自动推导, 即类型推导;
- 类型确定后, 就不能修改, 说明Scala是强数据类型语言;
- 变量声明时, 必须要有初始值;
- 在声明/定义一个变量时, 可以使用var/val修饰, var修饰的变量可改变, val修饰的变量不可改;
[案例一, 变量声明和赋值]
- 类型自动推导;
- 强类型语言;
- 声明变量时必须赋值;
- val的值不可变, var可变;
object TestValAndVar {
//1. 类型推导; 声明变量时, 类型可以忽略, 编译器会自动推导;
var a1 = 10;
var a2:Int = 10;
var b3 = "areusb?";
val c5 = false;
//2. 强类型语言; 变量/常量的数据类型确定后, 就不能再修改
var e3:Int = 250;
e3 = "feswgf"; //编译器不会对此句报错, 执行时才会报错 type mismatch, 看下图
//3. 声明变量时必须有初始值;
var e4:Int; // 抱错如下图所示
//4. var可变, va不可变
var f4 = 6;
f4 = 9;
val f5 = 100;
f5 = 200; //编译器当场报错;
def main(args : Array[String]): Unit = {
println(a1 + b3 + e4)
}
}
[案例二, var, val 在对象修改上的不同]
- var修饰的对象引用可以直接改变;
- val修饰的对象引用不可以改变, 但是对象的状态(引用的值)可以改变;
2.2 标识符
- Scala 对各种变量、方法、函数等命名时使用的字符序列称为标识符。即:凡是自己可以起名字的地方都叫标识符。
命名规则:
1. 字符,下划线,$开头, 后接字母,数字,下划线;
2. 以操作符开头, 且只包含操作符(+ - * / # ! 等 的任意组合)
3. 用反引号 ``包括的任意字符串, 即便是Scala关键字也可以这样作为标识符;
第一点跟Java命名规则是一致的, 下面2,3条简直是绝了, 闻所未闻的;
[案例: 分辨标识符正确与否]
- h-b不对, 是_ 这种叫下划线, 没有-这一说
- x h, 标识符中不能存在空格
- Int, 保留字不行, 加上``反引号倒是可以
- 有操作符的话, 就只能全是操作符, 所以 +*-/#!1 不对
- if 不对, 保留字
2.3 字符串
- 基本语法
- 字符串, 通过
+
号连接; - printf用法: 格式化字符串, 通过
%
传值; - 字符串模板(插值字符串): 通过
$
获取变量值;
object TestString {
def main(args: Array[String]): Unit = {
//1. + 字符串拼接, 另外, *是多次拼接字符串
var str1:String = "Hello !"
var str2:String = "Are u sb?"
println("'+'拼接字符串, "+str1 + str2)
println(str1*3) //Hello !Hello !Hello !
//2. printf, 格式化字符串.
// %d 整数, %s 字符串 , %f 输出浮点数
var name = "liming"
var age = 18
var grade = 88.26
printf("this is %s, and his age is %d , he got %2.3f in math exam;", name,age,grade)
println()
//3. 插值字符串(模板字符串),
// 3.1 插值字符串的写法: println(s"... ${变量名} ")
//3.2 如何填入变量值呢? ${变量名}, 插值就体现在这里
//1. 典型的插值字符串, println(s"待输入的字符串, 插入变量写为 ${变量名}")
println(s"${name} is my friend, his math got ${grade}, which is so so but better than me")
//2. 格式化的插值字符串, println(f" ${变量名}%d"),
// %%d 整数, %s 字符串 , %f 输出浮点数等等
println(f"this is a 格式化字符串, 比如: ${grade}%2.6f")
//3. 按照我们给定的字符串格式打印输出字符串, println(raw" ");
println(raw"我用了个 空格, %d本来是格式化字符串(输出整数), 使用了raw 原样输出了, ${name}, 但是插值还是能用的")
//4. 三引号, 保持多行字符串的原始格式输出
var ss = s"""
|我这个可是
|多行字符串输出噢, 甭管你是任何的
|格式化字符串, %d, %f, %u, 不管你, 但是
|插值还是可以用的噢
|""".stripMargin
println(ss)
}
}
拓展: Java中printf的用法
2.4 Scala键盘输入, 文件读写初探
- 语法:
- StdIn.readLine() 读取字符串
- StdIn.readShort() 读取Short类型的值
- StdIn.readDouble() 读取Double类型的值
- …
[案例: 键盘输入, 文件读写]
import java.io.{File, FileWriter}
import scala.io.{Source, StdIn}
object TestInAndOut {
def main(args: Array[String]): Unit = {
//读取字符串
println("请输入姓名: ")
val name: String = StdIn.readLine()
println("请输入年龄: ")
val age: Int = StdIn.readInt()
println(s"You are ${age}, your name is ${name}")
//读文件, Source.fromFile(path).foreach(print)
Source.fromFile("D:\\Code\\IdeaWorkSpace\\scala_demo\\src\\main\\resources\\read.txt").foreach(print)
//写文件, Scala写文件借助的还是Java 的IO流
val writer = new FileWriter(new File("D:\\Code\\IdeaWorkSpace\\scala_demo\\src\\main\\resources\\writeRes.txt"))
val outStr: String = "\"Scala读文件, Source.fromFile(path).foreach(print)\"";
writer.write(outStr)
writer.close()
}
}
2.5 Scala 数据类型
- Java中的数据类型
- Scala中的数据类型
2.5.1 Unit, Null, Nothing 类型
数据类型 | 描述 |
---|---|
Unit | 表示无值, 和其他语言中的void等同, 用作不返回任何结果的方法的结果类型; Unit只有一个实例值, 写成() |
Null | null, Null类型只有一个实例值null |
Nothing | Nothing类型处于Scala的类层级最底端, 他是任何其他类型的子类型; 当一个函数, 我们确定没有正常的返回值, 可以用Nothing来指定返回类型, 这样有一个好处, 就是我们可以把返回的值(异常)赋给其他的函数或者变量(兼容性) |
[案例]
- Unit 类型
- 用来标识过程, 也就是没有明确返回值的函数
为什么把Unit类型的方法打印输出是一对括号()? Unit源码分析:
- Null类
- 只有一个实例值,即null, 表示空引用
- Null类似于Java中的null引用.
- Null类可以赋值给任意引用类型(AnyRef), 但是不能赋值给值类型(AnyVal)
- Nothing
- 没有任何实例对象;
- 作为没有正常返回值的方法的返回类型, Nothing可以告诉你, 这个方法不会正常返回;
- 而且由于Nothing是其他任意类型的子类, 他还能跟要求返回值的方法兼容;
2.5.2 Scala 数据类型转换
Scala和Java 的数据类型转换是一致的,
- 数据从精度
小
的(数据类型表示范围小的)-->
精度大
的(数据类型表示范围大的), 会进行自动类型转换(隐式转换);- 相反, 由
大 --> 小
, 必须进行手动强制类型转换 xx.toInt
2.5.2.1 隐式转换
- Java, Scala 的自动转换
- 自动提升原则: 有多重类型的数据混合运算时, 系统首先将所有数据转换成精度大的那种数据类型, 然后再进行计算;
- 把精度大的数值类型复制给精度较小的数值类型时, 就会报错, 反之就会进行自动类型转换;
- (Byte, Short)这俩各自和 char之间不会相互自动转换
- 但是,Byte, Short, Char他们三者可以组合就散, 在计算时首先会自动转为Int类型;
2.5.2.2 强制类型转换
2.5.2.3 数值类型和 String类型之间的转换
实际的编程中, 经常能用到数值和字符串之间的互转, 来我们回忆下在Java中是怎样实现数值和字符串互转的:
数值==>字符串
, 会用到String类的包装方法, String.valueOf(数值变量)字符串==> 数值
, 根据数值对应的数据类型的不同, 数值的包装类.parse数值(数值变量), 比如, Integer.parseInt(intval)
那么, Scala是怎么进行转换的呢?
数值==>字符串
, 直接使用 +""拼接,字符串==> 数值
, 根据数值的数据类型不同, (s1.toInt, s1.toByte, s1.toLong, s1.toShort)
var n5:Int = “12.6”.toInt 会出现 NumberFormatException 异常。
来看一道面试题:(待补充)
三, 运算符
Scala 运算符的使用和 Java 运算符的使用基本相同,只有个别细节上不同。
3.1 算术运算符
3.2 关系运算符
Java和Scala中 == 和 equals()的异同点:
在Java中,
- 对于基本数据类型, ==是用来比较值的大小是否相等, 而对于
引用数据类型, ==用来比较引用的地址值是否相等
;- 另外, equals()作为Object类的方法, 通常是用来比较两个引用数据的地址是否相等, 然而在String, Integer, Date类中对equals()进行了重写, 用来比较两个值是否相等;
在Scala中,
- 由于Scala中的数据类型全是引用数据类型, 也就相对没有Java那么令人凌乱了, ==和 equals() 都是用来比较两个变量的值是否相等
- 而Scala用什么比较引用地址值?
Scala使用单独的一个 eq() 来比较两个对象的引用地址
object HelloWorld {
def main (args: Array[String]): Unit= {
//1. 比较值是否相等, ==或equals()
val num1: Int = 2
val num2: Int = 2
val str1: String = "liming"
val str2: String = "liming"
println("Scala使用 ==或quals() 来比较两个变量的值是否相等: ")
println("num1 和 num2 相等吗? " + (num1 == num2))
println("num1 和 num2 相等吗? " + (num1.equals(num2)))
println("str1 和 str2 相等吗? " + (str1 == str2))
println("str1 和 str2 相等吗? " + (str1.equals(str2)))
//2. 比较引用是否相等
println("=========================================")
println("Scala使用 eq() 比较两个变量引用的地址值是否相等")
println("num1 和 num2 的地址相等吗? " + (str1.eq(str2)))
}
}
3.3 赋值运算符
3.4 位运算符
- 位运算符是一种比较底层的计算方式,
- 按位左移, << , 移动n位, 就是把原数x2n
- 按位右移, >> , 移动m位, 就是把原数/2m, 除不尽的话就直接保留整数, 舍弃小数点;
Scala 运算符的本质(方法)
四, 流程控制
4.1 分支控制 if-else
分支控制让程序有选择的执行, 分支控制有三种: 单分支, 双分析, 多分支
- Scala中的分支控制逻辑基本与Java一致, 但是最大的不同在于,
Scala中的 if else{} 表达式是有返回值的
,
- 具体返回值内容取决于满足条件的分支代码体中的最后一行内容,
- 如果是一个字符串"", 那么就返回这一行字符串, 如果是一个变量, 或一个输出语句, 就返回()
- 注意: scala中if else表达式是有返回值的,且默认返回类型是Any类型,在根据实际返回的数值进行推断,如果if或者else返回的类型不一样,就返回Any类型(所有类型的公共超类型)。
- Java中的三元运算符可以用if else 实现
- Java的三元运算符:
判断条件 ? 条件为true的执行内容 : 条件为false的执行内容
- Scala的三元运算符: if(判断条件) 条件为true的执行内容 else 条件为false的执行内容
4.2 嵌套分支
(就上面的if-else 套娃呗, 没啥可讲的)
4.3 Switch 分支 (无, 使用模式匹配处理, 后面补充)
4.4 For 循环控制
Scala也为for循环这一常见的控制结构提供了非常多的特性, 这些for循环的特性被称为for推导式或for表达式;
4.4.1 范围数据循环(to)–> 左闭右闭
[基本用法]
// 把[0,10]的每一个整数, 循环赋值给i
for(i <- 0 to 10){
print(i + " ")
}
// 0 to 10 等同于 0.to(10), to就是方法噢
- i表示循环变量,
to表示的是循环从0到10(包括10)
如何倒序遍历? 加个reverse即可;
for(i <- 0 to 10 reverse){
print(i + " ")
}
4.4.2 范围数据循环(Until)–> 左闭右开
[基本用法]
// 把[0,10)的每一个整数, 循环赋值给i
for(i <- 0 until 10){
print(i + " ")
}
//或者使用下面这种方式, Range(a,b)
for(i <- Range(0,10)){
print(i + " ")
}
- i表示循环变量,
until表示的是循环从0到10(不包括10)
4.4.3 循环守卫( if xx)
- 循环守卫, 即循环保护式(或条件判断, 守卫)
- 保护式为true则进入循环体内部, 为false则跳过本次循环, 类似于continue
[基本用法]
for(i <- 1 to 3 if i != 2){
print(i + " ")
}
- 上面的写法等同于:
for(i <- 1 to 3){
if (i != 2){
print(i + " ")
}
}
4.4.4 循环步长(by)
[基本用法]
// 步长为2的循环遍历
// 注意噢, 步长不能为 0, 可以为正, 负, 浮点数(可能会精度出错)
for (i <- 0 to 10 by 2) {
println("i=" + i)
}
4.4.4 嵌套循环(多重循环)
[案例一, 九九乘法表]
object NineNideMultiple {
def main(args: Array[String]): Unit = {
//九九乘法表
//外层循环遍历1 to 9, 内层循环 i * (1 - > 9)
for(i <- 1 to 9){
for(j <- 1 to i){
print(s"${i} x ${j} = ${i * j} \t")
}
println()
}
println("========================================")
for(i <- 1 to 9; j <- 1 to i){
print(s"${i} x ${j} = ${i * j} \t")
if(j == i) println()
}
}
}
4.4.6 引入变量
4.4.7 循环返回值
4.5 While 和 do…While 循环控制
Scala中的While, do…While循环和Java中的用法完全一致
- 与 for 语句不同,while 语句没有返回值,即整个 while 语句的结果是 Unit 类型()
4.6 循环中断
Scala内置控制结构去掉了break和continue, 是为了更好的适应函数式编程, 推荐使用函数式的风格解决break和continue的功能, 而不是一个关键字.
Scala 中使用breakable 控制结构来实现break和continue功能
需求 1:采用异常的方式退出循环
def main(args: Array[String]): Unit = {
try {
for (elem <- 1 to 10) {
println(elem)
if (elem == 5) throw new RuntimeException
}
}catch {
//模式匹配
case e: Exception => //啥都不做. 退出循环
}
println("正常结束循环")
需求 2:采用 Scala 自带的函数,退出循环
import scala.util.control.Breaks
def main(args: Array[String]): Unit = {
Breaks.breakable(
for (elem <- 1 to 10) {
println(elem)
if (elem == 5) Breaks.break()
}
)
println("正常结束循环")
}
需求 3:对 break 进行省略
import scala.util.control.Breaks._
object TestBreak {
def main(args: Array[String]): Unit = {
breakable {
for (elem <- 1 to 10) {
println(elem)
if (elem == 5) break
}
}
println("正常结束循环")
}
}
需求 4:循环遍历 10 以内的所有数据,奇数打印,偶数跳过(continue)
object TestBreak {
def main(args: Array[String]): Unit = {
for (elem <- 1 to 10) {
if (elem % 2 == 1) {
println(elem)
} else {
println("continue")
}
}
}
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战