Scala's syntax is clean and expressive. Once you learn the patterns, you can write highly readable, concise code.
String Interpolation
Scala
val name = "Alice"
val age = 28
// s-interpolation (most common)
println(s"Name: $name, Age: $age")
println(s"Next year: ${age + 1}")
println(s"Uppercase: ${name.toUpperCase}")
// f-interpolation (formatted)
println(f"Pi is $pi%1.4f") // Pi is 3.1416
println(f"$name is $age%3d years old") // Alice is 28 years old
// raw-interpolation (escape sequences)
println(raw"Newline: \n") // Prints literal \nCollections Operations
Scala
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// Transformations
numbers.map(_ * 2) // List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
numbers.flatMap(x => List(x, x * 10)) // List(1,10,2,20,...)
numbers.filter(_ % 2 == 0) // List(2, 4, 6, 8, 10)
numbers.exists(_ > 5) // true
numbers.forall(_ > 0) // true
// Aggregations
numbers.sum // 55
numbers.product // 3628800
numbers.max // 10
numbers.min // 1
// Grouping
numbers.groupBy(_ % 3) // Map(0 -> List(3,6,9), 1 -> List(1,4,7,10), 2 -> List(2,5,8))
numbers.partition(_ > 5) // (List(6,7,8,9,10), List(1,2,3,4,5))
// Sorting
List(3, 1, 4, 1, 5).sorted // List(1, 1, 3, 4, 5)
List("banana", "apple").sorted // List("apple", "banana")
// Folding
numbers.foldLeft(0)(_ + _) // 55 (same as sum)
numbers.foldRight("")((n, acc) => s"$n $acc") // "10 9 8 7 6 5 4 3 2 1 "
// For comprehensions (syntactic sugar for map/flatMap/filter)
val result = for {
x <- List(1, 2, 3)
y <- List(10, 20)
if x > 1
} yield x * y
// List(20, 40, 30, 60)Option Type (Null Safety)
Scala
// Option replaces null — forces you to handle missing values
val maybeName: Option[String] = Some("Alice")
val emptyName: Option[String] = None
// Safe access
val length: Option[Int] = maybeName.map(_.length) // Some(5)
val upper: Option[String] = emptyName.map(_.toUpperCase) // None
// Unwrap with default
val name1 = maybeName.getOrElse("Anonymous") // "Alice"
val name2 = emptyName.getOrElse("Anonymous") // "Anonymous"
// Pattern matching
maybeName match {
case Some(name) => println(s"Found: $name")
case None => println("Not found")
}
// Chaining
def findUser(id: Int): Option[String] =
if (id == 1) Some("Alice") else None
val greeting: Option[String] = findUser(1).map(name => s"Hello, $name!")
// Some("Hello, Alice!")Error Handling with Try/Either
Scala
import scala.util.{Try, Success, Failure}
// Try — wraps code that might throw
def parseAge(input: String): Try[Int] = Try(input.toInt)
parseAge("25") match {
case Success(age) => println(s"Age: $age")
case Failure(e) => println(s"Invalid: ${e.getMessage}")
}
// Either — explicit success/failure types
def divide(a: Int, b: Int): Either[String, Int] =
if (b == 0) Left("Division by zero")
else Right(a / b)
divide(10, 3) match {
case Right(result) => println(s"Result: $result")
case Left(error) => println(s"Error: $error")
}
// Chaining with Either
val result: Either[String, Int] = for {
a <- Right(10)
b <- Right(3)
} yield a / b
// Right(3)For Comprehensions (Advanced)
Scala
// For comprehensions work with Option, Either, Try, Future, List...
def validateUser(name: String, age: String): Either[String, Int] = for {
n <- if (name.nonEmpty) Right(name) else Left("Name required")
a <- Try(age.toInt).toOption.toRight("Invalid age number")
_ <- if (a > 0 && a < 150) Right(()) else Left("Age out of range")
} yield a
validateUser("Alice", "28") // Right(28)
validateUser("", "28") // Left("Name required")
validateUser("Alice", "abc") // Left("Invalid age number")💡 Tip: Always use Option instead of null. Chain operations with
.map,.flatMap,.filterinstead of null checks. It makes code safer and more readable.
Next: Object-Oriented Scala