Skip to main content

Kotlin Object Expressions

Introduction

Object expressions in Kotlin provide a way to create anonymous objects - objects that are defined and instantiated in a single expression, without explicitly defining a class. If you're familiar with Java, you can think of them as similar to anonymous inner classes, but with a more concise syntax and additional capabilities.

Object expressions are particularly useful when you need to create a one-off implementation of an interface or extend a class without explicitly declaring a new named class.

Basic Syntax

The basic syntax of an object expression in Kotlin uses the object keyword followed by an optional supertype (interface or class) and a body:

kotlin
val myObject = object {
val property = "Hello"
fun method() = "World"
}

This creates an anonymous object with a property and a method. Here's how you can use it:

kotlin
fun main() {
println(myObject.property) // Output: Hello
println(myObject.method()) // Output: World
}

Implementing Interfaces with Object Expressions

One of the most common uses of object expressions is to implement interfaces on the fly:

kotlin
interface Greeter {
fun greet(): String
}

fun createGreeter(name: String): Greeter {
return object : Greeter {
override fun greet() = "Hello, $name!"
}
}

fun main() {
val greeter = createGreeter("Kotlin")
println(greeter.greet()) // Output: Hello, Kotlin!
}

In this example, we're creating an anonymous object that implements the Greeter interface and providing an implementation for the greet() function.

Extending Classes with Object Expressions

You can also use object expressions to create anonymous subclasses of existing classes:

kotlin
open class Animal(val name: String) {
open fun makeSound(): String = "Some generic sound"
}

fun createDog(name: String): Animal {
return object : Animal(name) {
override fun makeSound() = "Woof!"
}
}

fun main() {
val dog = createDog("Buddy")
println("${dog.name} says: ${dog.makeSound()}")
// Output: Buddy says: Woof!
}

Accessing Variables from the Enclosing Scope

Object expressions can access variables from the enclosing scope, unlike Java's anonymous inner classes which can only access final variables:

kotlin
fun createCounter(startValue: Int): () -> Int {
var count = startValue

return object {
fun next() = ++count
}::next
}

fun main() {
val counter = createCounter(5)
println(counter()) // Output: 6
println(counter()) // Output: 7
println(counter()) // Output: 8
}

In this example, the object expression captures the mutable count variable from its surrounding scope.

Multiple Interface Implementation

Object expressions can implement multiple interfaces at once:

kotlin
interface Clickable {
fun click()
}

interface Focusable {
fun focus()
}

val button = object : Clickable, Focusable {
override fun click() {
println("I was clicked")
}

override fun focus() {
println("I got focus")
}

fun sayHi() = println("Hi there!")
}

fun main() {
button.click() // Output: I was clicked
button.focus() // Output: I got focus
button.sayHi() // Output: Hi there!
}

Object Expressions vs. Object Declarations

It's important to distinguish between object expressions (what we've been discussing) and object declarations. Object expressions create instances that are used right away, while object declarations define singletons that can be referenced by name.

kotlin
// Object expression - creates an instance
val listener = object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
// handle click
}
}

// Object declaration - creates a singleton
object GlobalConfig {
var debugging = false
}

Practical Example: Event Listeners

One common use case for object expressions is creating event listeners, especially in UI programming:

kotlin
// Assuming we have a Button class
class Button {
private var clickListener: (() -> Unit)? = null

fun setOnClickListener(listener: () -> Unit) {
clickListener = listener
}

fun click() {
clickListener?.invoke()
}
}

fun main() {
val button = Button()

// Using an object expression to handle the click event
button.setOnClickListener {
println("Button was clicked!")
}

button.click() // Output: Button was clicked!
}

Practical Example: Custom Comparators

Another common use is creating custom comparators for sorting:

kotlin
data class Person(val name: String, val age: Int)

fun main() {
val people = listOf(
Person("Alice", 29),
Person("Bob", 31),
Person("Charlie", 25)
)

// Sort using an anonymous Comparator
val sortedByAge = people.sortedWith(
object : Comparator<Person> {
override fun compare(p1: Person, p2: Person): Int {
return p1.age - p2.age
}
}
)

println(sortedByAge)
// Output: [Person(name=Charlie, age=25), Person(name=Alice, age=29), Person(name=Bob, age=31)]
}

This could be shortened using Kotlin's SAM (Single Abstract Method) conversion, but the object expression version clearly shows the concept.

Summary

Kotlin object expressions provide a powerful way to create anonymous objects on the fly. They are useful for:

  • Creating one-time implementations of interfaces
  • Creating anonymous subclasses of existing classes
  • Implementing event listeners
  • Creating custom comparators
  • Any situation where you need an object with custom behavior but don't want to define a named class

Unlike Java's anonymous inner classes, Kotlin object expressions can access and modify variables from their enclosing scope, making them more flexible.

Exercises

  1. Create an object expression that implements a Runnable interface and prints "Running!" when its run() method is called.

  2. Define a function createLogger(tag: String) that returns an object with methods info(message: String) and error(message: String) which print formatted log messages with the given tag.

  3. Use an object expression to create a custom filter for a list of numbers that only lets even numbers pass through.

Additional Resources



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)