Scala 教程

Scala 教程

Scala(Scalable Language)是一门融合面向对象与函数式编程的 JVM 语言,由 Martin Odersky 于 2004 年发布,是 Apache Spark、Kafka 等大数据生态的核心语言。

本教程包含

  • 基础篇:简介、安装、语法、数据类型、变量、运算符
  • 控制篇:条件语句、循环、方法与函数、闭包
  • 进阶篇:字符串、数组、集合、类与对象、Trait、模式匹配、异常、文件 I/O

为什么学习 Scala

  • 函数式 + 面向对象双范式
  • 与 Java 无缝互操作
  • 大数据标配(Spark/Kafka/Flink)
  • 类型安全、表达力强、代码简洁

适合人群

Java 开发者转型、大数据工程师、函数式编程爱好者。

Scala 简介

Scala 简介

Scala 是一门运行在 JVM 上的静态类型语言,名字来源于 "Scalable Language"(可扩展语言)。

核心特性

  • 面向对象:一切皆对象,类、特质(Trait)、案例类(Case Class)
  • 函数式:函数是一等公民,不可变集合、模式匹配
  • 静态类型:强大的类型推断,兼顾安全与简洁
  • 与 Java 互操作:直接调用 Java 库
  • 并发友好:Akka 等并发框架基于 Scala

代码示例

object HelloWorld {
  def main(args: Array[String]): Unit = {
    println("Hello, Scala!")
  }
}

Scala vs Java 对比

// Java
List<Integer> nums = new ArrayList<>();
for (int i = 1; i <= 5; i++) nums.add(i * 2);

// Scala
val nums = (1 to 5).map(_ * 2)

应用领域

大数据(Spark)、流处理(Kafka/Flink)、Web 框架(Play/Lift)、分布式系统(Akka)。

Scala 安装及环境配置

Scala 安装及环境配置

Scala 需要 JVM 支持,安装前请确认 JDK 环境。

1. 安装 JDK

java -version   # 需要 JDK 8 或 11+(Scala 2.13 需 JDK 8+)

2. 安装 Scala

# macOS(Homebrew)
brew install scala

# Ubuntu/Debian
sudo apt install scala

# 或下载官方二进制包解压,配置 PATH

3. 验证安装

scala -version
# Scala code runner version 2.13.x

4. 推荐:使用 sbt(构建工具)

# 安装 sbt
brew install sbt

# 创建项目
sbt new scala/scala3.g8   # Scala 3
sbt new scala/hello-world.g8  # Scala 2 模板

5. IDE 支持

  • IntelliJ IDEA:Scala 插件(推荐)
  • VS Code:Metals 语言服务器
  • 命令行:scala file.scala 直接运行脚本

Scala 基础语法

Scala 基础语法

Scala 语法简洁灵活,但与 Java 有不少差异。

Hello World

object Hello {
  def main(args: Array[String]): Unit = {
    println("Hello, World!")
  }
}

程序结构

  • object:单例对象(程序的入口)
  • def:方法定义
  • main:入口方法
  • Unit:相当于 Java 的 void

基本语法规则

  • 语句末尾分号可选
  • 大小写敏感
  • 类名首字母大写,方法名首字母小写
  • 对象名(入口)大写开头

脚本方式运行

// hello.scala
println("Hello, Script!")

// 运行
scala hello.scala

注释

// 单行注释
/* 多行注释 */
/** 文档注释 */

包声明与导入

package com.example

import scala.collection.mutable
import java.util.{ArrayList, HashMap}

Scala 数据类型

Scala 数据类型

Scala 与 Java 一样有 8 种基础类型,但全部是对象,且支持类型推断。

基础数据类型

Byte    8位有符号整数
Short   16位有符号整数
Int     32位有符号整数
Long    64位有符号整数
Float   32位浮点
Double  64位浮点
Char    16位无符号字符
Boolean true/false
String  字符串(Java String)

字面量类型推断

val i = 10            // Int
val l = 10L           // Long
val f = 1.5f          // Float
val d = 1.5           // Double
val c = 'A'           // Char
val s = "Hello"       // String
val b = true          // Boolean

类型声明

val x: Int = 42       // 显式类型
val y = 42            // 类型推断
var z: Double = 3.14  // 可变变量

字符串与多行字符串

val s1 = "普通字符串"
val s2 = """多行
字符串
内容"""
val s3 = s"插值: ${s1} 长度 ${s1.length}"   // 字符串插值

Unit 与 Nothing

val u: Unit = ()      // 相当于 void
// Nothing:所有类型的子类型,异常返回值

Any 层级

Any(所有类型的根) → AnyVal(值类型) / AnyRef(引用类型)
Nothing(所有类型的子类型)

Scala 字面量

Scala 字面量

字面量是直接写在代码中的值,Scala 支持多种形式的字面量。

整数与浮点字面量

val a = 42            // 十进制
val b = 0x2A          // 十六进制
val c = 0b101010      // 二进制(Scala 2.13+)
val d = 42L           // Long
val e = 3.14          // Double
val f = 3.14f         // Float
val g = 1e6           // 科学计数法 Double

字符与字符串字面量

val ch = 'A'          // Char
val s1 = "Hello"      // String
val s2 = """多行
字符串"""              // 多行字符串(三引号)

布尔字面量

val t = true
val f = false

转义字符

val nl = "第一行
第二行"   // 换行
val tab = "a	b"           // 制表符
val quote = "他说: "你好""  // 双引号
val back = "反斜杠 \\"

符号字面量(弃用)

val sym = 'symbol   // Symbol 类型(旧写法,新代码用字符串)

null 与 Unit

val n = null         // 引用类型空值
val u = ()           // Unit 字面量

Scala 转义字符

Scala 转义字符

转义字符用于在字符串中表示特殊字符。

常用转义序列

\n    换行
\t    制表符
\\    反斜杠
\"    双引号
\'    单引号
\b    退格
\f    换页
\r    回车
\uXXXX  Unicode 字符(如 \u0041 = 'A')

示例

val path = "C:\\Users\\admin"    // C:\Users\admin
val say = "她说: \"你好!\""
val unicode = "\u4F60\u597D"      // 你好

多行字符串中无需转义

val regex = """\d+"""     // 三引号内反斜杠原样
val html = """<p>HTML 内容</p>"""

字符串插值中的转义

val name = "Scala"
val msg = s"你好, \$name"    // 输出: 你好, $name(字面$)
val msg2 = f"数字: ${3.14159}%.2f"  // 格式化: 3.14

注意事项

  • 正则表达式建议用三引号避免双重转义
  • 路径建议用正斜杠 C:/Users/admin

Scala 变量

Scala 变量

Scala 有 val(不可变)和 var(可变)两种变量,推荐优先使用 val。

val 与 var

val name = "Alice"    // 不可变(常量)
var age = 25          // 可变
age = 26              // 可以重新赋值
// name = "Bob"       // 编译错误: val 不能重新赋值

类型标注

val x: Int = 10
val y: String = "hi"
val list: List[Int] = List(1, 2, 3)

惰性变量

lazy val config = loadConfig()   // 首次访问时才计算
// 适合昂贵初始化、顺序无关的场景

变量命名

val user_name = "ok"     // 下划线风格
val userName = "ok"      // 驼峰风格(推荐)
val `type` = "特殊名"     // 反引号包裹保留字

val 与 Java final

Scala 的 val 类似 Java 的 final 变量;但 Scala 的 val 更严格(不可变引用)。

经验

  • 默认用 val,需要变更时才用 var
  • 集合优先用不可变集合
  • lazy val 避免重复计算

Scala 访问修饰符

Scala 访问修饰符

Scala 的访问修饰符有 private、protected 和默认(public),语义与 Java 略有差异。

三种修饰符

private   仅类内部可见
protected 类及子类可见(Java 同包可见,Scala 不同)
无修饰符  公开(public)

示例

class Person {
  private var name: String = "default"
  protected def greet(): Unit = println(s"Hi, $name")
  def setName(n: String): Unit = name = n   // 公开
}

作用域限定

// 限定到包
private[example] val x = 1    // example 包内可见

// 限定到类
private[Person] val y = 2     // Person 类内可见

protected 的差异

// Java: protected 成员同包也可访问
// Scala: protected 成员仅类及其子类可访问
class Base {
  protected def f(): Unit = println("base")
}
class Sub extends Base {
  def g() = f()   // 子类可访问
}
// new Base().f()  // 错误: 外部不可见

伴生对象访问

class Account {
  private var balance = 0.0
}
object Account {
  def show(a: Account) = a.balance   // 伴生对象可访问私有成员
}

Scala 中类和伴生对象之间没有访问限制。

Scala 运算符

Scala 运算符

Scala 中一切运算符都是方法调用,支持中缀语法。

算术运算符

+  -  *  /  %   加 减 乘 除 取余
val sum = 1 + 2       // 3
val sum2 = 1.+(2)     // 等价写法(方法调用)

关系运算符

==  !=  >  <  >=  <=
注意:Scala 的 == 比较值(自动调用 equals)

逻辑运算符

&&  ||  !   与 或 非
val ok = a > 0 && b < 10

位运算符

&  |  ^  ~  <<  >>  >>>
val r = 5 & 3      // 1

赋值运算符

+=  -=  *=  /=  %=
var n = 10
n += 5      // n = 15

比较 == 与 eq

val a = new String("hi")
val b = new String("hi")
a == b    // true(值相等)
a eq b    // false(引用相等)

自定义运算符

class Vector(val x: Double, val y: Double) {
  def +(other: Vector) = new Vector(x + other.x, y + other.y)
}
val v1 = new Vector(1, 2)
val v2 = new Vector(3, 4)
val v3 = v1 + v2    // 使用自定义 + 运算符

Scala IF...ELSE 语句

Scala IF...ELSE 语句

Scala 的 if-else 是表达式,有返回值,可以直接赋值给变量。

基本语法

val score = 85

if (score >= 90) {
  println("优秀")
} else if (score >= 60) {
  println("及格")
} else {
  println("不及格")
}

作为表达式赋值

val grade = if (score >= 90) "A"
            else if (score >= 80) "B"
            else if (score >= 60) "C"
            else "D"
// grade: String

单行写法

val max = if (a > b) a else b

三元运算符替代

// Java: int max = a > b ? a : b;
val max = if (a > b) a else b   // Scala 无三元运算符

类型问题

val result = if (flag) 1 else "no"
// 类型推断为 Any(共同超类型)

嵌套 if

if (x > 0) {
  if (y > 0) println("第一象限")
  else println("第四象限")
}

Scala 循环

Scala 循环

Scala 支持 while、do-while 和函数式风格的 for 推导式。

for 循环(推荐)

// 基础范围
for (i <- 1 to 5) println(i)       // 1..5 包含5
for (i <- 1 until 5) println(i)    // 1..4 不包含5

// 步长
for (i <- 1 to 10 by 2) println(i) // 1,3,5,7,9

// 嵌套
for (i <- 1 to 3; j <- 1 to 3) {
  println(s"$i x $j")
}

for 过滤(守卫)

for (i <- 1 to 10 if i % 2 == 0) println(i)  // 偶数
for (i <- 1 to 10; if i > 5; if i % 2 == 1) println(i)

for 推导式(生成集合)

val squares = for (i <- 1 to 5) yield i * i
// Vector(1, 4, 9, 16, 25)

while 循环

var n = 0
while (n < 5) {
  println(n)
  n += 1
}

do-while

var m = 0
do {
  println(m)
  m += 1
} while (m < 3)

break 与 continue

// Scala 2 无原生 break,用 Breaks 对象或递归
import scala.util.control.Breaks._
breakable {
  for (i <- 1 to 10) {
    if (i == 5) break
    println(i)
  }
}

Scala 方法与函数

Scala 方法与函数

方法(def)属于类,函数是对象(FunctionN),两者都支持函数式风格。

定义方法

def add(a: Int, b: Int): Int = {
  a + b
}
println(add(1, 2))    // 3

单行方法

def square(x: Int) = x * x   // 返回值类型可推断

无参方法

def greeting(): Unit = println("Hello")
def greeting2 = println("Hello")   // 无括号

默认参数

def greet(name: String, prefix: String = "Hello") = s"$prefix, $name"
greet("Alice")              // Hello, Alice
greet("Bob", "Hi")          // Hi, Bob

命名参数

def draw(x: Int, y: Int, color: String = "red") = ...
draw(color = "blue", x = 1, y = 2)   // 顺序任意

可变参数

def sum(nums: Int*): Int = nums.sum
sum(1, 2, 3)     // 6
sum(1, 2, 3, 4)  // 10

函数字面量(匿名函数)

val addOne: Int => Int = (x: Int) => x + 1
val addTwo = (x: Int) => x + 2        // 类型推断
val multiply = (a: Int, b: Int) => a * b

高阶函数

def applyTwice(f: Int => Int, x: Int): Int = f(f(x))
applyTwice(_ + 1, 5)    // 7

Scala 闭包

Scala 闭包

闭包是捕获了外部自由变量的函数,可以"记住"创建时的环境。

基本闭包

var factor = 2
val multiplier = (x: Int) => x * factor   // 捕获 factor
println(multiplier(5))    // 10

factor = 3                // 修改捕获的变量
println(multiplier(5))    // 15(引用最新值)

函数返回闭包

def counter(): () => Int = {
  var count = 0
  () => { count += 1; count }
}

val c1 = counter()
println(c1())   // 1
println(c1())   // 2
println(c1())   // 3

闭包的实际应用

// 柯里化
def addCurried(a: Int)(b: Int): Int = a + b
val add5 = addCurried(5)   // 闭包:捕获 a=5
add5(10)                   // 15

// 回调
def repeat(n: Int, f: () => Unit): Unit = {
  for (_ <- 1 to n) f()
}
repeat(3, () => println("hi"))

注意

  • 闭包捕获的是变量的引用,不是值快照
  • 不可变 val 捕获后保持不变
  • 闭包常用于回调、柯里化、延迟计算

Scala 字符串

Scala 字符串

Scala 的 String 本质是 java.lang.String,并扩展了丰富的操作。

创建字符串

val s1 = "Hello"
val s2 = new String("World")
val s3 = """多行
字符串"""

常用方法

val s = "Hello, Scala"
s.length          // 12
s.charAt(0)       // H
s.substring(0, 5) // Hello
s.toUpperCase     // HELLO, SCALA
s.toLowerCase     // hello, scala
s.trim            // 去空格
s.replace("Scala", "Java")
s.split(",")      // Array("Hello", " Scala")

字符串比较

val a = "abc"
val b = "abc"
a == b        // true(值比较)
a.equals(b)   // true
a.startsWith("ab")   // true
a.contains("bc")     // true

字符串插值(推荐)

val name = "Alice"
val age = 25
val msg = s"$name is $age years old"
val expr = s"1 + 2 = ${1 + 2}"
val price = f"价格: $age%.2f 元"    // 格式化
val raw = raw"\d+"                  // 不转义

字符串转换

"42".toInt
"3.14".toDouble
123.toString
Integer.parseInt("42")   // Java 互操作

字符串构建

val sb = new StringBuilder
sb.append("Hello").append(" ").append("World")
sb.toString()   // "Hello World"

Scala 数组

Scala 数组

Scala 数组分为定长 Array 和可变 ArrayBuffer。

创建数组

val a1 = new Array[Int](5)          // 空数组,默认0
val a2 = Array(1, 2, 3, 4, 5)       // 带初值
val a3 = Array.ofDim[String](3)     // 空字符串数组

访问与修改

val arr = Array(10, 20, 30)
arr(0)         // 10(注意用圆括号)
arr(0) = 99    // 修改
arr.length     // 3

遍历

for (x <- arr) println(x)
arr.foreach(println)
arr.map(_ * 2)         // 映射
arr.filter(_ > 15)     // 过滤

多维数组

val matrix = Array.ofDim[Int](3, 3)
matrix(0)(1) = 5

val m2 = Array(
  Array(1, 2),
  Array(3, 4)
)

数组与集合转换

val list = arr.toList
val seq = arr.toSeq
val set = arr.toSet
val back = list.toArray

ArrayBuffer(可变)

import scala.collection.mutable.ArrayBuffer
val buf = ArrayBuffer(1, 2, 3)
buf += 4            // 追加
buf ++= Array(5, 6) // 批量追加
buf.remove(0)       // 删除
buf(0)              // 访问

常用操作

arr.sum / arr.max / arr.min / arr.sorted
arr.indexOf(20)
arr.slice(1, 3)

Scala Collection(集合)

Scala Collection(集合)

Scala 集合库功能强大,默认推荐不可变集合。

集合分类

Seq(序列)   List / Vector / Range
Set(集合)   Set(无重复)
Map(映射)   Map(key -> value)

List(不可变)

val list = List(1, 2, 3)
list.head        // 1
list.tail        // List(2, 3)
list :+ 4        // List(1,2,3,4) 尾部追加(新列表)
4 :: list        // List(4,1,2,3) 头部插入
list.length      // 3

Set(不可变)

val set = Set(1, 2, 3, 3)   // Set(1, 2, 3) 自动去重
set + 4        // Set(1,2,3,4)
set - 2        // Set(1,3)
set.contains(2)  // true

Map(不可变)

val map = Map("a" -> 1, "b" -> 2)
map("a")           // 1
map.get("c")       // None(安全访问)
map + ("c" -> 3)   // 新增
map.keys           // Set(a, b)
map.values         // 值集合

常用高阶操作

val nums = List(1, 2, 3, 4, 5)
nums.map(_ * 2)        // List(2,4,6,8,10)
nums.filter(_ % 2 == 0) // List(2,4)
nums.reduce(_ + _)     // 15
nums.foldLeft(0)(_ + _) // 15
nums.sortBy(-_)        // 降序
nums.groupBy(_ % 2)    // 分组

可变集合

import scala.collection.mutable
val mList = mutable.ListBuffer(1, 2)
mList += 3

val mMap = mutable.Map("a" -> 1)
mMap("b") = 2

Scala Iterator(迭代器)

Scala Iterator(迭代器)

迭代器用于逐个访问集合元素,是惰性的,只能用一次。

创建迭代器

val it = Iterator(1, 2, 3, 4, 5)
val it2 = List(1, 2, 3).iterator
val it3 = (1 to 10).iterator

遍历

while (it.hasNext) {
  println(it.next())
}

// 或 foreach
val it4 = Iterator(1, 2, 3)
it4.foreach(println)

常用方法

it.size          // 剩余元素个数
it.length        // 同上
it.isEmpty
it.toList        // 转为集合
it.toArray
it.sum / it.max / it.min

映射与过滤(惰性)

val doubled = it.map(_ * 2)      // 不立即执行
doubled.foreach(println)         // 遍历时才计算

限制迭代器

it.take(3)        // 取前3个
it.drop(2)        // 跳过前2个
it.takeWhile(_ < 4)  // 直到条件不满足

注意事项

  • 迭代器是单次使用:遍历后即耗尽
  • 迭代器操作是惰性的,适合大数据流
  • 需要多次访问请转成集合
val it = Iterator(1, 2, 3)
it.foreach(println)   // 1 2 3
it.foreach(println)   // 空!已耗尽

Scala 类和对象

Scala 类和对象

Scala 类是蓝图,object 是单例,两者构成 Scala 的面向对象基础。

定义类

class Person(val name: String, var age: Int) {
  def greet(): Unit = println(s"Hi, I'm $name, $age years old")
}

val p = new Person("Alice", 25)
p.name       // 读取(自动生成 getter)
p.age = 26   // 修改(自动生成 setter)
p.greet()

主构造函数参数

class Point(val x: Int, val y: Int)   // val 生成 getter

// 无 val/var:参数只用于构造
class Config(host: String, port: Int) {
  def url = s"$host:$port"
}

辅助构造函数

class Person(val name: String) {
  def this() = this("Unknown")   // 辅助构造函数
  def this(name: String, age: Int) = {
    this(name)                   // 必须调用主构造
    println(s"created $name")
  }
}

Object 单例对象

object MathUtils {
  val PI = 3.14159
  def square(x: Double) = x * x
}
MathUtils.square(3)   // 9.0

伴生对象

class Circle(val r: Double) {
  def area = Circle.PI * r * r   // 访问伴生对象
}
object Circle {
  val PI = 3.14159
  def apply(r: Double) = new Circle(r)   // 工厂方法
}
Circle(2.0)   // apply 语法糖,不需要 new

案例类(Case Class)

case class User(id: Int, name: String)
val u = User(1, "Alice")     // 无需 new
u.name                       // 自动 getter
u.copy(name = "Bob")         // 拷贝修改
u == User(1, "Alice")        // true 值比较

Scala Trait(特征)

Scala Trait(特征)

Trait 类似 Java 接口,但可以包含具体实现,支持多继承,是 Scala 组合复用的核心。

定义 Trait

trait Greeter {
  def greet(name: String): String        // 抽象方法
  def welcome(): String = "Welcome!"     // 具体实现
}

混入 Trait

class EnglishGreeter extends Greeter {
  override def greet(name: String) = s"Hello, $name"
}

// 混入多个 Trait
class MyClass extends BaseClass with TraitA with TraitB

富接口模式

trait Ordered[T] {
  def compare(that: T): Int
  def <(that: T) = compare(that) < 0    // 由 compare 派生
  def >(that: T) = compare(that) > 0
}

case class Money(amount: Double) extends Ordered[Money] {
  def compare(that: Money) = amount.compare(that.amount)
}

Trait 字段

trait Logger {
  val level: String              // 抽象字段
  def log(msg: String): Unit = println(s"[$level] $msg")
}

class AppLogger extends Logger {
  val level = "INFO"
}

线性化(菱形问题解决)

trait A { def f() = println("A") }
trait B extends A { override def f() = { super.f(); println("B") } }
trait C extends A { override def f() = { super.f(); println("C") } }
class D extends B with C          // 调用顺序: A → C → B
new D().f()   // A C B

与抽象类的选择

需要继承多个 → 用 Trait
需要构造参数 → 用抽象类(Trait 参数受限)

Scala 模式匹配

Scala 模式匹配

模式匹配是 Scala 的杀手级特性,类似增强版 switch,可以匹配值、类型、结构、case class。

基本匹配

val x = 3
val result = x match {
  case 1 => "one"
  case 2 => "two"
  case _ => "other"     // 通配符
}

匹配守卫

val n = 15
n match {
  case x if x % 2 == 0 => s"$x 是偶数"
  case x if x % 3 == 0 => s"$x 是3的倍数"
  case _ => "其他"
}

匹配类型

def describe(obj: Any): String = obj match {
  case s: String => s"字符串: $s"
  case i: Int => s"整数: $i"
  case l: List[_] => s"列表,长度 ${l.length}"
  case _ => "未知类型"
}

匹配 Case Class

case class Point(x: Int, y: Int)
case class Circle(center: Point, r: Double)

val shape: Any = Circle(Point(0, 0), 5.0)
shape match {
  case Circle(Point(x, y), r) => s"圆心($x,$y) 半径$r"
  case Point(x, y) => s"点($x,$y)"
  case _ => "未知"
}

匹配集合

val list = List(1, 2, 3)
list match {
  case Nil => "空列表"
  case head :: tail => s"头部:$head 尾部:$tail"
  case _ => "其他"
}

Option 匹配

val maybe: Option[Int] = Some(42)
maybe match {
  case Some(v) => s"有值: $v"
  case None => "无值"
}

Scala 正则表达式

Scala 正则表达式

Scala 通过 scala.util.matching.Regex 封装了 Java 正则,使用更简洁。

创建正则

import scala.util.matching.Regex

val pattern = new Regex("\d+")
val pattern2 = Regex("\d+")
val pattern3 = """\d+""".r          // 推荐:字符串插值.r 语法

查找

val nums = """\d+""".r
nums.findFirstIn("order 1001 total 50")   // Some(1001)
nums.findAllIn("a1 b22 c333").toList      // List(1, 22, 333)
nums.findFirstMatchIn("x42").map(_.start) // Some(1)

匹配判断

"""^\d+$""".r.matches("12345")     // true
"""^\d+$""".r.matches("12ab")      // false

提取组

val email = """([a-z]+)@([a-z]+)\.([a-z]+)""".r
val email(user, domain, tld) = "alice@example.com"
// user=alice, domain=example, tld=com

替换

val text = "price: 100, discount: 20"
"""[0-9]+""".r.replaceAllIn(text, "#")   // price: #, discount: #
"""[0-9]+""".r.replaceFirstIn(text, "#")

分割

"""[,\s]+""".r.split("a, b c")   // Array(a, b, c)

常用正则示例

"""\d{11}""".r            // 11位数字
"""[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}""".r  // 邮箱
"""https?://[\w./-]+""".r  // URL

Scala 异常处理

Scala 异常处理

Scala 的异常处理与 Java 类似,但 try-catch-finally 是表达式。

抛出异常

throw new IllegalArgumentException("参数非法")
// 注意: Scala 没有 checked exception(不强制捕获)

捕获异常

try {
  val result = riskyOperation()
  println(result)
} catch {
  case e: ArithmeticException => println("算术错误")
  case e: Exception => println(s"其他异常: ${e.getMessage}")
} finally {
  println("清理资源")
}

异常作为表达式

val result = try {
  "10".toInt
} catch {
  case _: NumberFormatException => 0
} finally {
  println("尝试转换")
}
// result: Int

自定义异常

class BusinessException(message: String) extends Exception(message)

try {
  throw new BusinessException("业务校验失败")
} catch {
  case e: BusinessException => println(e.getMessage)
}

函数式错误处理

// 用 Try 替代异常(函数式风格)
import scala.util.{Try, Success, Failure}

val result: Try[Int] = Try("42".toInt)
result match {
  case Success(v) => println(s"成功: $v")
  case Failure(e) => println(s"失败: ${e.getMessage}")
}

// Option 风格
"42".toIntOption    // Some(42)
"abc".toIntOption   // None

推荐实践

  • 业务错误用 Option/Try/Either 表达
  • 系统异常(IO等)用 try-catch
  • finally 释放资源(或 use using)

Scala 提取器(Extractor)

Scala 提取器(Extractor)

提取器是定义了 unapply 方法的对象,用于模式匹配时从对象中提取值,是实现自定义模式匹配的机制。

apply 与 unapply

object Email {
  // apply: 构造
  def apply(user: String, domain: String) = s"$user@$domain"

  // unapply: 提取(模式匹配用)
  def unapply(email: String): Option[(String, String)] = {
    val parts = email.split("@")
    if (parts.length == 2) Some(parts(0), parts(1))
    else None
  }
}

// 构造
val e = Email("alice", "example.com")

// 模式匹配提取
"alice@example.com" match {
  case Email(user, domain) => s"用户$user, 域名$domain"
  case _ => "非法邮箱"
}

单值提取器

object Twice {
  def unapply(x: Int): Option[Int] =
    if (x % 2 == 0) Some(x / 2) else None
}

8 match {
  case Twice(n) => s"8 是 $n 的两倍"   // 4
}

Boolean 提取器

object IsPositive {
  def unapply(x: Int): Boolean = x > 0
}

5 match {
  case IsPositive() => "正数"
  case _ => "非正数"
}

与 Case Class 的关系

// case class 自动生成 unapply,所以可直接模式匹配
case class Point(x: Int, y: Int)

// 自定义提取器实现同样效果
object Point {
  def apply(x: Int, y: Int) = new Point(x, y)
  def unapply(p: Point): Option[(Int, Int)] = Some((p.x, p.y))
}

Scala 文件 I/O

Scala 文件 I/O

Scala 标准库没有专门的 I/O 包,但可以直接使用 Java I/O 类,或借助 scala.io 简化读取。

读取文件(整文件)

import scala.io.Source

val source = Source.fromFile("data.txt", "UTF-8")
try {
  val content = source.mkString    // 全部内容
  println(content)
} finally {
  source.close()
}

逐行读取

val source = Source.fromFile("data.txt")
try {
  for (line <- source.getLines()) {
    println(line)
  }
} finally {
  source.close()
}

读取网络内容

val source = Source.fromURL("https://example.com")
val content = source.mkString
source.close()

写入文件

import java.io.{PrintWriter, File}

val writer = new PrintWriter(new File("out.txt"))
try {
  writer.write("第一行\n")
  writer.println("第二行")
} finally {
  writer.close()
}

追加写入

import java.io.{FileWriter, BufferedWriter}

val bw = new BufferedWriter(new FileWriter("log.txt", true))
bw.write("追加内容\n")
bw.close()

使用 Using(自动关闭)

import scala.util.Using

Using(Source.fromFile("data.txt")) { source =>
  source.mkString
}
// 自动关闭资源,返回 Try[String]

其他常用操作

import java.nio.file.{Files, Paths}

val lines = Files.readAllLines(Paths.get("data.txt"))
Files.write(Paths.get("out.txt"), "内容".getBytes)
第 1 / 25 节