How do I use delegation by `by` keyword to implement interfaces or properties in Kotlin?

In Kotlin, the by keyword is used for delegation. It lets one object delegate behavior to another object instead of implementing everything manually.

There are two common forms:

  1. Interface/class delegation
  2. Property delegation

1. Interface delegation

If a class implements an interface, it can delegate the implementation of that interface to another object using by.

Example

interface Printer {
    fun print(message: String)
}

class ConsolePrinter : Printer {
    override fun print(message: String) {
        println(message)
    }
}

class LoggingPrinter(
    private val printer: Printer
) : Printer by printer

Here, LoggingPrinter implements Printer, but the actual implementation is delegated to printer.

Usage:

fun main() {
    val printer = LoggingPrinter(ConsolePrinter())
    printer.print("Hello Kotlin")
}

Output:

Hello Kotlin

LoggingPrinter does not need to manually implement print() because Printer by printer forwards calls to the given printer.


Overriding delegated behavior

You can still override specific methods if you want custom behavior.

interface Printer {
    fun print(message: String)
}

class ConsolePrinter : Printer {
    override fun print(message: String) {
        println(message)
    }
}

class LoggingPrinter(
    private val printer: Printer
) : Printer by printer {
    override fun print(message: String) {
        println("Logging message: $message")
        printer.print(message)
    }
}

Now calls to print() use the overridden method in LoggingPrinter.

fun main() {
    val printer = LoggingPrinter(ConsolePrinter())
    printer.print("Hello Kotlin")
}

Output:

Logging message: Hello Kotlin
Hello Kotlin

2. Delegating multiple interfaces

A class can delegate multiple interfaces to different objects.

interface Reader {
    fun read(): String
}

interface Writer {
    fun write(value: String)
}

class FileReader : Reader {
    override fun read(): String = "file contents"
}

class ConsoleWriter : Writer {
    override fun write(value: String) {
        println(value)
    }
}

class FileProcessor(
    reader: Reader,
    writer: Writer
) : Reader by reader, Writer by writer

Usage:

fun main() {
    val processor = FileProcessor(FileReader(), ConsoleWriter())

    val text = processor.read()
    processor.write(text)
}

Important note about delegated members

If a delegated object calls one of its own methods internally, it does not dispatch to overrides in the delegating class.

interface Service {
    fun operation()
    fun run()
}

class DefaultService : Service {
    override fun operation() {
        println("Default operation")
    }

    override fun run() {
        operation()
    }
}

class CustomService(
    private val service: Service
) : Service by service {
    override fun operation() {
        println("Custom operation")
    }
}

Usage:

fun main() {
    val service = CustomService(DefaultService())
    service.operation()
    service.run()
}

Output:

Custom operation
Default operation

service.run() is delegated to DefaultService.run(), and inside that object, operation() resolves to DefaultService.operation().


Property delegation

Property delegation lets another object provide the getter and/or setter for a property.

The syntax is:

val propertyName: Type by delegate
var propertyName: Type by delegate

The delegate object must provide:

  • getValue(...) for val
  • getValue(...) and setValue(...) for var

1. Built-in property delegates

Kotlin provides several common delegates.


lazy

lazy initializes a value only when it is first accessed.

val expensiveValue: String by lazy {
    println("Computing value")
    "Hello"
}

fun main() {
    println("Before access")
    println(expensiveValue)
    println(expensiveValue)
}

Output:

Before access
Computing value
Hello
Hello

The initializer runs only once.


observable

Delegates.observable runs code whenever a property changes.

import kotlin.properties.Delegates

var name: String by Delegates.observable("Unknown") { property, oldValue, newValue ->
    println("${property.name} changed from $oldValue to $newValue")
}

fun main() {
    name = "Alice"
    name = "Bob"
}

Output:

name changed from Unknown to Alice
name changed from Alice to Bob

vetoable

Delegates.vetoable can reject a new value.

import kotlin.properties.Delegates

var age: Int by Delegates.vetoable(0) { _, _, newValue ->
    newValue >= 0
}

fun main() {
    age = 25
    println(age)

    age = -5
    println(age)
}

Output:

25
25

The assignment to -5 is rejected.


notNull

Delegates.notNull() is useful for non-null properties initialized later.

import kotlin.properties.Delegates

var username: String by Delegates.notNull()

fun main() {
    username = "alice"
    println(username)
}

If you read username before assigning it, Kotlin throws an exception.


Custom property delegate

You can create your own delegate by implementing getValue and optionally setValue.

import kotlin.reflect.KProperty

class LoggingDelegate {
    private var value: String = ""

    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        println("Reading ${property.name}")
        return value
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: String) {
        println("Writing ${property.name}: $newValue")
        value = newValue
    }
}

class User {
    var name: String by LoggingDelegate()
}

Usage:

fun main() {
    val user = User()

    user.name = "Alice"
    println(user.name)
}

Output:

Writing name: Alice
Reading name
Alice

How getValue and setValue work

For:

var name: String by LoggingDelegate()

Kotlin roughly translates property access like this:

val delegate = LoggingDelegate()

delegate.setValue(thisRef, property, "Alice")
val value = delegate.getValue(thisRef, property)

The signatures are:

operator fun getValue(thisRef: Any?, property: KProperty<*>): T
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T)

For top-level properties, thisRef is null.


Delegating to another property

You can also delegate one property to another property reference.

class User {
    var name: String = "Alice"

    var displayName: String by this::name
}

fun main() {
    val user = User()

    println(user.displayName)

    user.displayName = "Bob"

    println(user.name)
}

Output:

Alice
Bob

displayName delegates its storage to name.


Delegating to a map

A common pattern is delegating properties to a Map.

class User(
    private val data: Map<String, Any?>
) {
    val name: String by data
    val age: Int by data
}

Usage:

fun main() {
    val user = User(
        mapOf(
            "name" to "Alice",
            "age" to 30
        )
    )

    println(user.name)
    println(user.age)
}

Output:

Alice
30

For mutable properties, use MutableMap:

class MutableUser(
    private val data: MutableMap<String, Any?>
) {
    var name: String by data
    var age: Int by data
}

Summary

Use case Syntax Meaning
Interface delegation class C(d: I) : I by d Forward interface calls to d
Lazy property val x by lazy { ... } Compute once on first access
Observable property var x by Delegates.observable(...) React to changes
Vetoable property var x by Delegates.vetoable(...) Accept or reject changes
Custom delegate var x by MyDelegate() Delegate getter/setter logic
Map-backed property val x: T by map Read value from map by property name
Property reference var x by this::other Delegate to another property

In short:

class MyClass(delegate: SomeInterface) : SomeInterface by delegate

is for interface delegation, while:

val value by lazy { ... }
var name by MyDelegate()

is for property delegation.

How do I define constructors and initialize class properties in Kotlin?

In Kotlin, you usually define constructors and initialize properties directly in the class header using a primary constructor.

1. Primary constructor

The most common style is:

class Person(val name: String, var age: Int)

This defines:

  • a class named Person
  • a read-only property name
  • a mutable property age
  • a constructor that requires both values

Usage:

fun main() {
    val person = Person("Alice", 30)

    println(person.name)
    println(person.age)

    person.age = 31
    println(person.age)
}

Here, val name: String and var age: Int are both constructor parameters and class properties.


2. Constructor parameters without properties

If you omit val or var, the parameter is only available during initialization:

class Person(name: String) {
    val uppercaseName = name.uppercase()
}

Usage:

fun main() {
    val person = Person("Alice")

    println(person.uppercaseName)
}

In this example, name is not a property. You cannot access person.name unless you declare it with val or var.


3. Initialize properties in the class body

You can initialize properties using constructor values:

class Rectangle(val width: Int, val height: Int) {
    val area: Int = width * height
}

Usage:

fun main() {
    val rectangle = Rectangle(5, 4)

    println(rectangle.area)
}

Output:

20

4. Use an init block

If you need validation or setup logic, use an init block:

class User(val username: String, val age: Int) {
    init {
        require(username.isNotBlank()) {
            "Username must not be blank"
        }

        require(age >= 0) {
            "Age must not be negative"
        }
    }
}

The init block runs when an object is created:

fun main() {
    val user = User("kotlinFan", 25)

    println(user.username)
}

5. Default constructor values

You can give constructor parameters default values:

class Product(
    val name: String,
    val price: Double = 0.0,
    val inStock: Boolean = true
)

Usage:

fun main() {
    val freeSample = Product("Sticker")
    val laptop = Product("Laptop", 999.99, false)

    println(freeSample.price)
    println(laptop.inStock)
}

6. Named arguments

Named arguments make constructor calls clearer:

class Book(
    val title: String,
    val author: String,
    val pages: Int
)

fun main() {
    val book = Book(
        title = "Kotlin Basics",
        author = "JetBrains",
        pages = 250
    )

    println(book.title)
}

7. Secondary constructors

Kotlin also supports secondary constructors, but they are less common:

class Car {
    val brand: String
    val year: Int

    constructor(brand: String, year: Int) {
        this.brand = brand
        this.year = year
    }
}

Usage:

fun main() {
    val car = Car("Toyota", 2024)

    println(car.brand)
    println(car.year)
}

However, this is usually better written with a primary constructor:

class Car(val brand: String, val year: Int)

8. Primary and secondary constructors together

If a class has a primary constructor, secondary constructors must delegate to it using this(...):

class Employee(val name: String, val role: String) {
    constructor(name: String) : this(name, "Employee")
}

Usage:

fun main() {
    val employee = Employee("Sam")
    val manager = Employee("Dana", "Manager")

    println(employee.role)
    println(manager.role)
}

9. Late initialization with lateinit

For mutable non-null properties initialized later, use lateinit var:

class Session {
    lateinit var token: String

    fun start(token: String) {
        this.token = token
    }
}

Usage:

fun main() {
    val session = Session()

    session.start("abc123")

    println(session.token)
}

Use lateinit carefully. Accessing it before initialization causes an exception.


10. Custom getters and setters

You can customize property access:

class Temperature(celsius: Double) {
    var celsius: Double = celsius
        set(value) {
            require(value >= -273.15) {
                "Temperature cannot be below absolute zero"
            }
            field = value
        }

    val fahrenheit: Double
        get() = celsius * 9 / 5 + 32
}

Usage:

fun main() {
    val temperature = Temperature(25.0)

    println(temperature.fahrenheit)

    temperature.celsius = 30.0
    println(temperature.fahrenheit)
}

Quick summary

class Person(
    val name: String,
    var age: Int = 0
) {
    init {
        require(name.isNotBlank()) {
            "Name cannot be blank"
        }
    }

    val isAdult: Boolean
        get() = age >= 18
}

This example shows:

  • val name: read-only property initialized from constructor
  • var age: mutable property with a default value
  • init: validation logic
  • isAdult: computed property

In most Kotlin code, prefer a primary constructor with val or var properties unless you specifically need more complex construction logic.

How do I read a value from properties file using Spring EL?

In the previous two examples you have seen how to access member of a collection and access a map element using the square-braces [] operator in Spring EL. In this example you will see how to use the [] operator to read a value from a properties file or java.util.Properties.

Let’s say we have a database properties file called database.properties with the following entries in it:

jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/kodejava
jdbc.username=root
jdbc.password=secret

First, let’s create the spring configuration file. In this configuration we will use the <util:properties> to load the properties file into Spring. And then we will use Spring EL to access the value of these properties and assign it to some bean’s properties.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <util:properties id="database" location="classpath:database.properties" />

    <bean id="dataSource" class="org.kodejava.spring.core.el.MyDataSource">
        <property name="driverClassName" value="#{database['jdbc.driverClassName']}" />
        <property name="url" value="#{database['jdbc.url']}" />
        <property name="username" value="#{database['jdbc.username']}" />
        <property name="password" value="#{database['jdbc.password']}" />
    </bean>
</beans>

To read a value from properties file what you do is the same as how we access an element of a map object. We pass the name of the properties as the key in the Spring EL.

<property name="driverClassName" value="#{database['jdbc.driverClassName']}"/>

The MyDataSource class is an imaginary data source object. It has some properties such as the driverClassName, url, username and password. It’s a common parameter you use to connect to a database using a JDBC driver. For simplicity the getters and setters we removed from the class.

package org.kodejava.spring.core.el;

public class MyDataSource {
    private String driverClassName;
    private String url;
    private String username;
    private String password;

    // Getters & Setters
}

As always, to run the Spring configuration above we will need to create a main class that load and execute the application context. This class will obtain the dataSource bean from the application context and print out its properties whose values are read from a properties file called database.properties.

package org.kodejava.spring.core.el;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpELPropertiesExample {
    public static void main(String[] args) {
        try (ClassPathXmlApplicationContext context =
                     new ClassPathXmlApplicationContext("spel-properties.xml")) {

            MyDataSource dataSource = (MyDataSource) context.getBean("dataSource");
            System.out.println("driverClassName = " + dataSource.getDriverClassName());
            System.out.println("url             = " + dataSource.getUrl());
            System.out.println("username        = " + dataSource.getUsername());
            System.out.println("password        = " + dataSource.getPassword());
        }
    }
}

Here are the result you get when running the code snippet:

driverClassName = com.mysql.cj.jdbc.Driver
url             = jdbc:mysql://localhost/kodejava
username        = root
password        = secret

Maven Dependencies

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>5.3.23</version>
    </dependency>
</dependencies>

Maven Central Maven Central Maven Central

What are the system properties used for sending email?

Here are a list of system properties that can be used to send an e-mail using the JavaMail API.

Property Default Value Description
mail.host Define the host name of the mail server.
mail.smtp.host Define the host name of the SMTP server; this will overrides the mail.host for SMTP connections only.
mail._protocol_.host Define the host name of the specified protocol (POP, IMAP); this will overrides the mail.host.
mail.user Define the default username sent to all mail servers.
mail._protocol_.user Define the default username for the specified protocol; this will overrides the mail.user for the specified protocol.
mail.smtp.port 25 Define the SMTP port on which the SMTP server is listening.
mail._protocol_.port Default port for the corresponding protocol Define the port on which the servers for the specified protocol is listening.
mail.smtp.starttls.enable Upgrade the regular SMTP connection on the usual port to an encrypted (TLS or SSL) connection.
mail.smtp.connectiontimeout Infinite Define the number of milliseconds to wait for a connection timeout.
mail.debug false Define parameter for disabling or enabling information debugging.
mail.from Define the e-mail address to use in the From header.
mail.mime.charset file.encoding Define the default character set used to send messages.
mail.alternates Define other email address for the current that will not to be included when replying to a message.
mail._protocol_.class Define the fully package qualified class name of the provider for the specified protocol.
mail.transport.protocol First transport provider in the configuration file Define default protocol with which to send messages.
mail.transport.protocol.address-type Define the message transport protocol such as SMTP for the specified address type, for example mail.transport.protocol.rfc822.
mail.replayallcc false Put all recipients in the CC list of the reply message instead of the TO field when replying to all.

How to establish connection to a database using Properties object?

In the following code snippet, you will see how to pass some connection arguments when connecting to a database. To do this, we can use the java.util.Properties class. We can put some key value pairs as a connection arguments to the Properties object
before we pass this information into the DriverManager class.

Let’s see the example below:

package org.kodejava.jdbc;

import java.sql.*;
import java.util.Properties;

public class GetConnectionWithProperties {
    private static final String URL = "jdbc:mysql://localhost/kodejava";
    private static final String USERNAME = "kodejava";
    private static final String PASSWORD = "s3cr*t";

    public static void main(String[] args) {
        GetConnectionWithProperties demo = new GetConnectionWithProperties();
        try (Connection connection = demo.getConnection()) {
            // do something with the connection.
            Statement stmt = connection.createStatement();
            ResultSet rs = stmt.executeQuery("SELECT * FROM product");
            while (rs.next()) {
                System.out.println("Code = " + rs.getString("code"));
                System.out.println("Name = " + rs.getString("name"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private Connection getConnection() throws SQLException {
        Properties connectionProps = new Properties();
        connectionProps.put("user", USERNAME);
        connectionProps.put("password", PASSWORD);

        Connection connection = DriverManager.getConnection(URL, connectionProps);
        System.out.println("Connected to database.");
        return connection;
    }
}

Maven Dependencies

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.4.0</version>
</dependency>

Maven Central