Scala Conditional Statements

Scala provides multiple conditional control structures, including if-else statements, match expressions, and more. Unlike Java, all conditional statements in Scala are expressions and return values.

if-else Expression

Basic if-else

object BasicIfElse {
  def main(args: Array[String]): Unit = {
    val age = 18
    
    // Basic if-else
    if (age >= 18) {
      println("Adult")
    } else {
      println("Minor")
    }
    
    // if-else as expression
    val status = if (age >= 18) "Adult" else "Minor"
    println(s"Status: $status")
    
    // Single-line if-else
    val message = if (age >= 18) "Can vote" else "Cannot vote"
    println(message)
  }
}

Multiple if-else

object MultipleIfElse {
  def main(args: Array[String]): Unit = {
    val score = 85
    
    val grade = if (score >= 90) {
      "A"
    } else if (score >= 80) {
      "B"
    } else if (score >= 70) {
      "C"
    } else if (score >= 60) {
      "D"
    } else {
      "F"
    }
    
    println(s"Score: $score, Grade: $grade")
    
    // More complex conditions
    val temperature = 25
    val weather = if (temperature > 30) {
      "Hot"
    } else if (temperature > 20) {
      "Warm"
    } else if (temperature > 10) {
      "Cool"
    } else {
      "Cold"
    }
    
    println(s"Temperature: ${temperature}°C, Weather: $weather")
  }
}

Nested if-else

object NestedIfElse {
  def main(args: Array[String]): Unit = {
    val age = 25
    val hasLicense = true
    val hasInsurance = true
    
    val canDrive = if (age >= 18) {
      if (hasLicense) {
        if (hasInsurance) {
          "Can drive"
        } else {
          "Needs insurance"
        }
      } else {
        "Needs license"
      }
    } else {
      "Not old enough"
    }
    
    println(canDrive)
    
    // Simplified using logical operators
    val canDriveSimple = if (age >= 18 && hasLicense && hasInsurance) {
      "Can drive"
    } else {
      "Cannot drive"
    }
    
    println(canDriveSimple)
  }
}

Match Expression

Basic Match Expression

object BasicMatch {
  def main(args: Array[String]): Unit = {
    val dayOfWeek = 3
    
    val dayName = dayOfWeek match {
      case 1 => "Monday"
      case 2 => "Tuesday"
      case 3 => "Wednesday"
      case 4 => "Thursday"
      case 5 => "Friday"
      case 6 => "Saturday"
      case 7 => "Sunday"
      case _ => "Invalid day"  // Default case
    }
    
    println(s"Day $dayOfWeek is $dayName")
    
    // Match strings
    val fruit = "apple"
    val color = fruit match {
      case "apple" => "Red"
      case "banana" => "Yellow"
      case "orange" => "Orange"
      case "grape" => "Purple"
      case _ => "Unknown color"
    }
    
    println(s"$fruit color is $color")
  }
}

Conditional Match

object ConditionalMatch {
  def main(args: Array[String]): Unit = {
    val number = 15
    
    val description = number match {
      case n if n < 0 => "Negative"
      case n if n == 0 => "Zero"
      case n if n > 0 && n < 10 => "Single digit positive"
      case n if n >= 10 && n < 100 => "Two digit positive"
      case _ => "Large number"
    }
    
    println(s"$number is $description")
    
    // Match ranges
    val grade = 85
    val level = grade match {
      case g if g >= 90 => "Excellent"
      case g if g >= 80 => "Good"
      case g if g >= 70 => "Medium"
      case g if g >= 60 => "Pass"
      case _ => "Fail"
    }
    
    println(s"Score $grade corresponds to level $level")
  }
}

Type Matching

object TypeMatching {
  def main(args: Array[String]): Unit = {
    def processValue(value: Any): String = value match {
      case s: String => s"String: $s"
      case i: Int => s"Integer: $i"
      case d: Double => s"Floating point: $d"
      case b: Boolean => s"Boolean: $b"
      case list: List[_] => s"List with ${list.length} elements"
      case map: Map[_, _] => s"Map with ${map.size} entries"
      case _ => "Unknown type"
    }
    
    println(processValue("Hello"))        // String: Hello
    println(processValue(42))             // Integer: 42
    println(processValue(3.14))           // Floating point: 3.14
    println(processValue(true))           // Boolean: true
    println(processValue(List(1, 2, 3)))  // List with 3 elements
    println(processValue(Array(1, 2)))    // Unknown type
  }
}

Collection Matching

object CollectionMatching {
  def main(args: Array[String]): Unit = {
    def analyzeList(list: List[Int]): String = list match {
      case Nil => "Empty list"
      case head :: Nil => s"Single element: $head"
      case head :: tail => s"Head: $head, Tail length: ${tail.length}"
    }
    
    println(analyzeList(List()))           // Empty list
    println(analyzeList(List(1)))          // Single element: 1
    println(analyzeList(List(1, 2, 3)))    // Head: 1, Tail length: 2
    
    // Match specific patterns
    def matchPattern(list: List[Int]): String = list match {
      case List(1, 2, 3) => "Exactly 1, 2, 3"
      case List(1, _*) => "List starting with 1"
      case List(_, _, 3) => "Three element list with third element 3"
      case x :: y :: _ if x > y => "First two elements decreasing"
      case _ => "Other pattern"
    }
    
    println(matchPattern(List(1, 2, 3)))     // Exactly 1, 2, 3
    println(matchPattern(List(1, 4, 5)))     // List starting with 1
    println(matchPattern(List(2, 1, 3)))     // Three element list with third element 3
    println(matchPattern(List(5, 3, 1)))     // First two elements decreasing
  }
}

Advanced Conditional Expressions

Option Type Conditional Handling

object OptionConditionals {
  def main(args: Array[String]): Unit = {
    def findUser(id: Int): Option[String] = {
      if (id > 0) Some(s"User$id") else None
    }
    
    val userId = 5
    val user = findUser(userId)
    
    // Use match to handle Option
    val message = user match {
      case Some(name) => s"Found user: $name"
      case None => "User does not exist"
    }
    println(message)
    
    // Use if-else to handle Option
    val result = if (user.isDefined) {
      s"Username: ${user.get}"
    } else {
      "User not found"
    }
    println(result)
    
    // Use getOrElse
    val userName = user.getOrElse("Anonymous user")
    println(s"User: $userName")
  }
}

Functional Conditional Handling

object FunctionalConditionals {
  def main(args: Array[String]): Unit = {
    val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    
    // Use filter for conditional filtering
    val evenNumbers = numbers.filter(_ % 2 == 0)
    println(s"Even numbers: $evenNumbers")
    
    // Use partition to split
    val (evens, odds) = numbers.partition(_ % 2 == 0)
    println(s"Evens: $evens")
    println(s"Odds: $odds")
    
    // Use find to locate
    val firstEven = numbers.find(_ % 2 == 0)
    println(s"First even: $firstEven")
    
    // Use exists to check existence
    val hasEven = numbers.exists(_ % 2 == 0)
    println(s"Contains even numbers: $hasEven")
    
    // Use forall to check all
    val allPositive = numbers.forall(_ > 0)
    println(s"All positive: $allPositive")
  }
}

Practical Examples

Grade Management System

case class Student(name: String, score: Int)

object GradeSystem {
  def getGrade(score: Int): String = score match {
    case s if s >= 90 => "A"
    case s if s >= 80 => "B"
    case s if s >= 70 => "C"
    case s if s >= 60 => "D"
    case _ => "F"
  }
  
  def getStatus(score: Int): String = {
    if (score >= 60) "Pass" else "Fail"
  }
  
  def analyzeStudent(student: Student): String = {
    val grade = getGrade(student.score)
    val status = getStatus(student.score)
    
    student.score match {
      case s if s >= 95 => s"${student.name}: Excellent student ($grade, $status)"
      case s if s >= 85 => s"${student.name}: Good student ($grade, $status)"
      case s if s >= 60 => s"${student.name}: Average student ($grade, $status)"
      case _ => s"${student.name}: Needs help ($grade, $status)"
    }
  }
  
  def main(args: Array[String]): Unit = {
    val students = List(
      Student("Zhang San", 95),
      Student("Li Si", 87),
      Student("Wang Wu", 72),
      Student("Zhao Liu", 45)
    )
    
    students.foreach(student => println(analyzeStudent(student)))
  }
}

Simple State Machine

sealed trait State
case object Idle extends State
case object Running extends State
case object Paused extends State
case object Stopped extends State

class StateMachine(private var currentState: State = Idle) {
  def transition(action: String): State = {
    currentState = (currentState, action) match {
      case (Idle, "start") => Running
      case (Running, "pause") => Paused
      case (Running, "stop") => Stopped
      case (Paused, "resume") => Running
      case (Paused, "stop") => Stopped
      case (Stopped, "reset") => Idle
      case (state, _) => 
        println(s"Invalid transition: $state -> $action")
        state
    }
    currentState
  }
  
  def getCurrentState: State = currentState
}

object StateMachineExample {
  def main(args: Array[String]): Unit = {
    val machine = new StateMachine()
    
    println(s"Initial state: ${machine.getCurrentState}")
    println(s"After start: ${machine.transition("start")}")
    println(s"After pause: ${machine.transition("pause")}")
    println(s"After resume: ${machine.transition("resume")}")
    println(s"After stop: ${machine.transition("stop")}")
    println(s"After reset: ${machine.transition("reset")}")
  }
}

Best Practices

  1. Prioritize expressions: Take advantage of conditional statements returning values in Scala
  2. Use match instead of multiple if-else: When there are multiple conditions, match is clearer
  3. Avoid deep nesting: Use logical operators or early returns to reduce nesting
  4. Use Option to handle potentially null values: Avoid null pointer exceptions
  5. Leverage pattern matching power: Match types, collection structures, etc.

Mastering conditional control structures is the foundation for writing logically clear and maintainable code.