第1章 Scala 入门与环境
Scala 是什么、为什么值钱(Spark / Flink 都在用它)、环境怎么装、第一个程序怎么写。
本章学习目标
- 能说出 Scala 与 Java 的关系,以及它在 JVM 生态里的位置
- 能区分函数式与面向对象两种写法,并知道 Scala 两者都支持
- 能装好 JDK + sbt / scala-cli,跑通第一个 HelloWorld
- 会用 REPL 做小段试验
本章导览
核心内容
1.1
Scala 是什么:JVM 上的函数式 + 面向对象
看清 Scala 的定位:JVM 上的函数式与面向对象合体。
能说出 Scala 与 Java、JVM 的关系能各举一个函数式与面向对象的 Scala 写法知道这门课用 Scala 2.13 + sbt 来练手
知识点
一门跑在 JVM 上的静态语言
- Scala 源码编译成 JVM 字节码,能直接调用 Java 类库。
- 静态类型:类型错误在编译期暴露,不等到运行时才炸。
- 同时支持面向对象与函数式,两种风格可以在一个文件里混写。
和 Java 像,但不是 Java 方言
- object 定义单例,val 定义不可变值,def 定义方法,语法比 Java 紧凑。
- Java 的类、接口、集合在 Scala 里都能用,Scala 类也能被 Java 调用。
- 没有 static、没有 i++、没有三目运算符,对应写法后面会逐一讲。
为什么值得学
- Spark、Kafka 等组件大量使用 Scala,Flink 也提供 Scala API,读源码和调 API 常常绕不开它。
- 函数式写法让集合处理、并发和测试更简单,表达力强。
- 代价是类型系统和隐式规则学习曲线陡,前期先把语法用熟。
本课版本口径
- 全课以 Scala 2.13 + sbt 为准,示例都在 2.13 上编译运行。
- 遇到 Scala 3 不同处(given/using、缩进语法、enum)会单独注明,不混用两种语法。
代码示例
▶ REPL 初体验:集合操作与样例类
$ scala
scala> val nums = List(1, 2, 3, 4)
nums: List[Int] = List(1, 2, 3, 4)
scala> nums.filter(_ % 2 == 0).map(_ * 10)
res0: List[Int] = List(20, 40)
scala> case class User(name: String, age: Int)
defined class User
scala> User("小明", 18).copy(age = 19)
res1: User = User(小明,19)👀 运行结果
List(1, 2, 3, 4) List(20, 40) defined class User User(小明,19)
▶ 直接调用 Java 的集合类
object Interop {
def main(args: Array[String]): Unit = {
val list = new java.util.ArrayList[String]()
list.add("a")
list.add("b")
println(list.size())
println(list)
}
}👀 运行结果
2 [a, b]
▶ 递归 + if 表达式:一个方法完成阶乘
object Factorial {
def fact(n: Int): Int =
if (n <= 1) 1 else n * fact(n - 1)
def main(args: Array[String]): Unit =
println(fact(5))
}👀 运行结果
120
常见错误
⚠️ 踩坑与解决
在 .scala 文件顶层直接写 def main,报 expected class or object definition
→ Scala 2 的源文件顶层只允许 package、class、object、trait,顶层方法没有宿主。;把代码包进 object,例如 object Hello { def main(args: Array[String]): Unit = ... },或先在 REPL 里试。PowerShell 输入 scala 提示“无法将 scala 项识别为 cmdlet”
→ 没装 Scala 发行版,或者安装目录没有加进 PATH。;先用 sbt console 启动 REPL;或安装 Scala CLI 后重开终端再执行 scala-cli。
💡 把 REPL 当草稿纸:语法拿不准就先敲两行验证,再写进文件。
1.2
环境搭建与第一个程序(JDK、sbt / scala-cli、IDEA、REPL)
装好 JDK 与 sbt,跑通 HelloWorld 和 REPL。
能检查 JDK 版本并配好 JAVA_HOME能用 sbt 运行一个 Scala 2.13 项目能在 REPL 里验证表达式与退出
知识点
JDK 是地基
- Scala 编译器和程序都跑在 JVM 上,先装 JDK 11 或 17 这类 LTS 版本。
- 命令行执行 java -version 和 javac -version,确认两个命令来自同一套 JDK。
- 把 JAVA_HOME 指向 JDK 根目录,并把它的 bin 目录加进 PATH。
sbt 管项目
- 项目根目录的 build.sbt 写 scalaVersion := "2.13.14",源码放在 src/main/scala。
- sbt compile 编译,sbt run 运行,sbt console 进 REPL,sbt clean 清理。
- 第一次运行会下载 sbt 插件和 Scala 依赖,网络慢时多等一会,不要急着改配置。
scala-cli 与 IDEA
- 单个 .scala 文件用 scala-cli run Hello.scala 更轻,不必先建完整的 sbt 工程。
- scala-cli 默认可能选 Scala 3;跑本课代码时加 --scala 2.13.14,避免语法对不上。
- IDEA 装 Scala 插件后导入 sbt 项目,代码补全和调试更顺手。
- 本课示例都能用 sbt 跑,build.sbt 里的 scalaVersion 固定为 2.13。
代码示例
▶ build.sbt 与 Hello.scala 分两个文件写:最小可运行项目
// 文件 1:build.sbt
scalaVersion := "2.13.14"
// 文件 2:src/main/scala/Hello.scala
object Hello {
def main(args: Array[String]): Unit = {
println("你好,Scala 2.13")
}
}👀 运行结果
$ sbt run [info] compiling 1 Scala source to ...\target\scala-2.13\classes ... [info] running Hello 你好,Scala 2.13 [success] Total time: 1 s
▶ sbt console:不建类也能试语法
$ sbt console
scala> val name = "Scala"
name: String = Scala
scala> s"Hello, $name!"
res0: String = Hello, Scala!
scala> List(1, 2, 3).sum
res1: Int = 6
scala> :quit👀 运行结果
name: String = Scala res0: String = Hello, Scala! res1: Int = 6
▶ 给 main 传命令行参数
object HelloArgs {
def main(args: Array[String]): Unit = {
val who = if (args.isEmpty) "world" else args.mkString(", ")
println(s"Hello, $who!")
}
}👀 运行结果
$ sbt "run Alice Bob" [info] running HelloArgs Alice Bob Hello, Alice, Bob! [success] Total time: 1 s
常见错误
⚠️ 踩坑与解决
命令行提示 java 不是内部或外部命令
→ JDK 没装,或者 JAVA_HOME / PATH 没有配好。;安装 JDK 17,重新打开终端,用 java -version 和 javac -version 验证。sbt run 报 [error] No main class detected
→ 当前项目没有带 main 方法的 object,或者源码没有放在 src/main/scala 下。;检查 object 里有 def main(args: Array[String]): Unit,文件在 src/main/scala,再执行 sbt run。
💡 第一次 sbt 会下载依赖和编译插件,卡几分钟很正常;先等它跑完,再判断是不是配置出错。