Scala - Case Classes



Case class in Scala is used to define objects that are public and immutable by default. There are many built-in methods available in case class. You have to use case keywords to define case class and object in Scala.

Case Classes apply, unapply, and copy Methods

Case class has several methods, like apply and unapply. The apply method acts as constructor and the unapply method provides pattern matching. You can use the apply method to create instances of a case class. You can use the unapply method to decompose instances during pattern matching. Case class also has a copy method that creates copies and modifies instances.

Syntax

The syntax of the case classes in Scala -

case class Person(name: String, age: Int)

Here, the case class Person is defined with two fields: name and age. So, the compiler generates apply method for creating instances. The unapply method is used for pattern matching.

Example

Try the following example program of the Person case class -

case class Person(name: String, age: Int)

object Demo {
   def main(args: Array[String]) = {
      val person = Person("Zara", 25)

      // Using the apply method to create an instance
      println(s"Created person: $person")

      // Using the unapply method for pattern matching
      person match {
         case Person(name, age) => println(s"Name: $name, Age: $age")
         case _ => println("Not a person")
      }

      // Using the copy method to create a modified copy
      val olderPerson = person.copy(age = 30)
      println(s"Older person: $olderPerson")
   }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

Created person: Person(Zara,25)
Name: Zara, Age: 25
Older person: Person(Zara,30)

Pattern Matching with Case Classes

You can work with pattern matching using case classes. You can decompose and match instances easily. The unapply method is automatically generated and extracts the fields of case class during pattern matching.

We will define a case class Person. We will use pattern matching to decompose instances of the case class.

Syntax

case class Person(name: String, age: Int)

def greet(person: Person) = person match {
   case Person(name, age) if age < 18 => s"Hello, $name! You're a minor."
   case Person(name, age) => s"Hello, $name!"
}

Example

Try the following example program of pattern matching with a case class -

case class Person(name: String, age: Int)

object Demo {
   case class Person(name: String, age: Int)

   def greet(person: Person) = person match {
      case Person(name, age) if age < 18 => s"Hello, $name! You're a minor."
      case Person(name, age) => s"Hello, $name!"
   }

   def main(args: Array[String]) = {
      val person1 = Person("Nuha", 16)
      val person2 = Person("Ayan", 21)

      println(greet(person1))
      println(greet(person2))
   }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

Hello, Nuha! You're a minor.
Hello, Ayan!

In this example, there is greet function. It uses pattern matching for different cases based on the age of the Person.

Copying Case Class Instances

There is copy method that is built-in method of case class. You can modify copies of instances after copying these from original. This method is used to create new instances with some fields. So, you can change these fields and keep the rest unchanged.

Let us take an example of using the copy method with a case class. We will define a case class Person and use the copy method to create a modified copy of an instance.

Syntax

case class Person(name: String, age: Int)

val person = Person("Maira", 25)
val olderPerson = person.copy(age = 30)

Example

Try the following example program of copy method with a case class -

case class Person(name: String, age: Int)

object Demo {
   case class Person(name: String, age: Int)

   def main(args: Array[String]) = {
      val person = Person("Maira", 25)
      println(s"Original person: $person")

      val olderPerson = person.copy(age = 30)
      println(s"Older person: $olderPerson")
   }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

Original person: Person(Maira,25)
Older person: Person(Maira,30)

In this example, a copy method is used. It creates and then modifies copy of the Person instance with different age.

Equality and Hashing

Case classes have implementations of equals and hashCode methods based on the values of the fields. So, it is easy to compare instances and use these in collections that depend on hashing, like sets and maps.

Consider a case class Person and use equality and hashing with instances. Let us take an example of using equality and hashing with a case class. We will define a case class Person and compare instances for equality and use them in a set.

Syntax

case class Person(name: String, age: Int)

val person1 = Person("Nuha", 25)
val person2 = Person("Nuha", 25)
val person3 = Person("Ayan", 30)

println(person1 == person2) // true
println(person1 == person3) // false

val people = Set(person1, person2, person3)
println(people) 

Example

Try the following example program of equality and hashing with a case class -

case class Person(name: String, age: Int)

object Demo {
   case class Person(name: String, age: Int)

   def main(args: Array[String]) = {
      val person1 = Person("Nuha", 25)
      val person2 = Person("Nuha", 25)
      val person3 = Person("Ayan", 30)

      println(person1 == person2) // true
      println(person1 == person3) // false

      val people = Set(person1, person2, person3)
      println(people)
   }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

true
false
Set(Person(Nuha,25), Person(Ayan,30))

In this example, there are equals and hashCode methods. These are used to compare instances of the Person case class and to store them in a set.

Case Objects

Case objects are similar to case classes but are used for singleton objects. Case objects have many common features of case classes. For example, both are serializable and have default hashCode implementation.

Consider a case object Employee. It has more features over regular objects. Let us take an example of using a case object. We will define a case object Employee.

Syntax

case object Employee {
   val name = "Zara"
   val age = 23
}

Example

Try the following example program of a case object -

case object Employee {
   val name = "Zara"
   val age = 23
}

object Demo {
   case object Employee {
      val name = "Zara"
      val age = 23
   }

   def main(args: Array[String]) = {
      println(s"Name of the employee is ${Employee.name}")
      println(s"Age of the employee is ${Employee.age}")
   }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

Name of the employee is Zara
Age of the employee is 23

Difference Between Class and Case Class

The following table shows the key differences between class and case class −

Feature Class Case Class
Constructor Parameters Private by default Public and immutable by default
Apply Method Not available by default Automatically generated
Unapply Method Not available by default Automatically generated
Pattern Matching Not supported Supported
equals and hashCode Must be defined manually Automatically generated
toString Must be defined manually Automatically generated
Copy Method Not available by default Automatically generated
Companion Object Not generated automatically Automatically generated
Inheritance from Another Case Class Supported Not supported

Case Classes Summary

  • Case classes are used to define public and immutable
  • Case classes also provide various in-built methods, like apply(), unapply(), copy(), etc.
  • The apply method creates instances and unapply method is used for pattern matching.
  • You can copy instances of case class using the copy method.
  • You can decompose and match instances easily using case classes.
  • Case classes have implementations of equals and hashCode methods based on the values of the fields.
  • Case objects are similar to case classes but used for singleton objects.
  • Scala compiler generates methods like apply, unapply, equals, hashCode, toString, and copy for case classes.
Advertisements