Skip to main content

CS 3100: Program Design and Implementation II

Lecture 36: Kotlin: A Better Java

©2026 Ellen Spertus, CC-BY-SA

Learning Objectives

After this lecture, you will be able to explain the benefits of these Kotlin features:

  • Nullable types
  • Named and default arguments
  • Top-level functions
  • Type inference
  • Conditional expressions
    • if expressions
    • switch expressions

Semester Grades: Labs

GradeTotal PointsIndividual AssignmentsGroup AssignmentsExamsLabsParticipation
A≥900≥240 (80%)≥160 (80%)≥280 (70%)≥11 completed≥40 (80%)
B≥800≥210 (70%)≥140 (70%)≥220 (55%)≥9 completed≥25 (50%)
C≥700≥180 (60%)≥120 (60%)≥200 (50%)≥7 completed
D≥600
F<600 or fails to meet above minimums

There are 14 labs; each is worth 5 points, with the total capped at 50 points (allowing you to miss a few without penalty).

For example, if you attend 10 labs, you get 50 points and can earn a B (possibly a B+).

Poll: Why do/don't you attend class/lecture when ungraded?

Poll Everywhere QR Code or Logo

Text espertus to 22333 if the
URL isn't working for you.

https://pollev.com/espertus

This poll is anonymous but counts toward participation.

Poll: What's your least favorite thing about Java?

Poll Everywhere QR Code or Logo

Text espertus to 22333 if the
URL isn't working for you.

https://pollev.com/espertus

This is a word cloud poll, so answer briefly, with hyphens separating words (e.g., null-pointers)

Common Criticisms of Java

  • Verbosity and boilerplate code

  • Everything must be in a class

  • Lack of null-safety

  • Checked exceptions

What Is Kotlin?

  • Created by JetBrains (makers of IntelliJ IDEA), released 2016
  • Designed to be fully interoperable with Java — runs on the JVM
  • Goals: fix Java's pain points while staying familiar to Java developers
  • In 2017, Google named it a first-class language for Android
  • Today used in Android, backend (Spring), and multiplatform development

Java and Kotlin on the JVM

Java

static int cube(int x) {
return x * x * x;
}
public static void main(String[] args) {
System.out.println(cube(3));
}

Kotlin

fun cube(x: Int) = x * x * x

fun main() {
println(cube(3))
}
⬇️ compiler ⬇️

Byte Code

static cube(I)I        public static main(Ljava/lang/String;)V
ILOAD 0 L0
ILOAD 0 LINENUMBER 8 L0
IMUL GETSTATIC System.out : Ljava/io/PrintStream;
ILOAD 0 ICONST_3
IMUL INVOKESTATIC Main.cube (I)I
IRETURN INVOKEVIRTUAL java/io/PrintStream.println (I)V
JVM ➡️27

What differences can you spot?

Java

public class MyClass {
static int cube(int x) {
return x * x * x;
}

public static void main(String[] args) {
System.out.println(cube(3));
}
}

Kotlin

fun cube(x: Int) = x * x * x

fun main() {
println(cube(3))
}

Some Differences

Java

public class MyClass {
static int cube(int x) {
return x * x * x;
}

public static void main(String[] args) {
System.out.println(cube(3));
}
}

Kotlin

fun cube(x: Int) = x * x * x

fun main() {
println(cube(3))
}
  • No semicolons
  • Code outside class (top-level functions)
  • Visibility defaults to public
  • fun keyword
  • Different parameter lists
    • name followed by : and type
    • all types are capitalized (objects)
  • A function body can be an expression
  • Return type can be inferred

Transforming describeItems()

Java

// describeItems(1, "rock") => "1 rock"
// describeItems(2, "rock") => "2 rocks"
static String describeItems(
int quantity, String item) {
String description = quantity + " " + item;
if (quantity != 1) {
return description + "s";
} else {
return description;
}
}

public static void main(String[] args) {
System.out.println(describeItems(1, "rock"));
System.out.println(describeItems(2, "rock"));
}

Kotlin

// describeItems(1, "rock") => "1 rock"
// describeItems(2, "rock") => "2 rocks"
fun describeItems(
quantity: Int, item: String): String {
val description = quantity.toString() + " " + item
if (quantity != 1) {
return description + "s"
} else {
return description
}
}

fun main() {
println(describeItems(1, "rock"))
println(describeItems(2, "rock"))
}

Kotlin variables are declared with

  • val (immutable)
  • var (mutable)

https://pl.kotl.in/KhDNBlWcH

Transformation

fun describeItems(
quantity: Int, item: String): String {
val description =
quantity.toString() + " " + item
if (quantity != 1) {
return description + "s"
} else {
return description
}
}
fun describeItems(
quantity: Int, item: String) =
"$quantity $item" +
if (quantity != 1) "s" else ""

Changes:

  • String templates
  • Return type omitted
  • Return statement omitted
  • if-expression value used

You Transform 3-Argument Max

Java

static int max(int a, int b, int c) {
if (a >= b && a >= c) {
return a;
} else if (b >= c) {
return b;
} else {
return c;
}
}

Kotlin

fun max(a: Int, b: Int, c: Int): Int {
if (a >= b && a >= c) {
return a
} else if (b >= c) {
return b
} else {
return c
}
}

https://pl.kotl.in/vbnzB1wzd

Transformation

Before

fun max(a: Int, b: Int, c: Int): Int {
if (a >= b && a >= c) {
return a
} else if (b >= c) {
return b
} else {
return c
}
}

After

fun max(a: Int, b: Int, c: Int) =
if (a >= b && a >= c) a
else if (b >= c) b
else c

Nullable Types

In Java, any reference can be null:

String name = null;
System.out.println(name.length()); // NullPointerException at runtime

In Kotlin, non-nullable is the default:

var name: String = null  // does not compile
var name: String? = null // ok — question mark indicates nullability

Safe Call Operator ?.

Kotlin won't let you call methods on a nullable type without handling the null case:

var name: String? = null
println(name.length) // does not compile

The safe call operator returns null instead of throwing an exception:

println(name?.length)  // prints null

Chains short-circuit at the first null:

println(user?.address?.city)  // prints null if any part is null

Exercise: Nullable Types

Java

record Client(PersonalInfo personalInfo) {}
record PersonalInfo(String email) {}
interface Mailer {
void sendMessage(String email, String message);
}

void sendMessageToClient(
@Nullable Client client,
@Nullable String message,
@NotNull Mailer mailer) {

// Try to extract email address
if (client == null) return;
PersonalInfo info = client.personalInfo();
if (info == null) return;
String email = info.email();

if (email == null || message == null) return;

mailer.sendMessage(email, message);
}

Kotlin

class Client(val personalInfo: PersonalInfo?)
class PersonalInfo(val email: String?)
interface Mailer {
fun sendMessage(email: String, message: String)
}

fun sendMessageToClient(
client: Client?,
message: String?,
mailer: Mailer
) {
// Extract email address or set to null
val email = TODO()

// Can't send if there is no email or message
if (email == null || message == null) {
return
}

mailer.sendMessage(email, message)
}

https://pl.kotl.in/toXWp7eW9

Transformation

Java

void sendMessageToClient(
@Nullable Client client,
@Nullable String message,
@NotNull Mailer mailer) {

// Try to extract email address
if (client == null) return;
PersonalInfo info = client.personalInfo();
if (info == null) return;
String email = info.email();

if (email == null || message == null) return;

mailer.sendMessage(email, message);
}

Kotlin

fun sendMessageToClient(
client: Client?,
message: String?,
mailer: Mailer
) {
val email = client?.personalInfo?.email
if (email == null || message == null) {
return
}
mailer.sendMessage(email, message)
}

Kotlin Koan: Smart Casts

interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr

fun eval(expr: Expr): Int =
when (expr) {
is Num -> TODO()
is Sum -> TODO()
else -> throw IllegalArgumentException(
"Unknown expression")
}

https://play.kotlinlang.org/koans/Classes/Smart%20casts/Task.kt

Kotlin Koan: Sealed Classes

fun eval(expr: Expr): Int =
when (expr) {
is Num -> TODO()
is Sum -> TODO()
} a + (b ?: 0) + (c ?: 0)

interface Expr
class Num(val value: Int) : TODO()
class Sum(val left: Expr, val right: Expr) : TODO()

https://play.kotlinlang.org/koans/Classes/Sealed%20classes/Task.kt

The Elvis Operator ?:

The Elvis operator returns a default value when the left side is null:

val name: String? = null
println(name ?: "Unknown") // Unknown

val length = name?.length ?: 0 // 0

This replaces the common null-check pattern:

// Without Elvis
val display = if (name != null) name else "Unknown"

// With Elvis
val display = name ?: "Unknown"

Why "the Elvis Operator"?

Graphic showing that a rotated '?:' looks like Elvis Presley's hair and eyes

Elvis Operator: Example

Java

static int add3(int a, Integer b, Integer c) {
return a
+ (b != null ? b : 0)
+ (c != null ? c : 0);
}

Kotlin

fun add3(a: Int, b: Int?, c: Int?): Int {
var result = a
if (b != null) {
result = result + b
} else {
result = result + 0
}
if (c != null) {
result = result + c
} else {
result = result + 0
}
return result
}

https://pl.kotl.in/GpeGlDC96

Transformation

Before

fun add3(a: Int, b: Int?, c: Int?): Int {
var result = a
if (b != null) {
result = result + b
} else {
result = result + 0
}
if (c != null) {
result = result + c
} else {
result = result + 0
}
return result
}

After

fun add3(a: Int, b: Int?, c: Int?) =
a + (b ?: 0) + (c ?: 0)

Extension Functions

Can you add a new method to an existing class whose source code you don't have?

Not in Java, but in Kotlin...

fun String.truncate(maxLength: Int): String {
return if (this.length <= maxLength) this else take(maxLength - 3) + "..."
}

// Hint: Use the String method reversed()
fun String.isPalindrome(): Boolean = TODO()

fun main() {
val shortUsername = "KotlinFan42"
val longUsername = "JetBrainsLoverForever"

println("Short username: ${shortUsername.truncate(15)}")
println("Long username: ${longUsername.truncate(15)}")

// println("wow".isPalindrome()) // true
// println("woo".isPalindrome()) // false
}

https://pl.kotl.in/RWcXCXM3p

Poll: Which Kotlin feature excites you most?

A. Null safety (no more NullPointerExceptions)

B. Default and named arguments (no more overloads)

C. Data classes (no more boilerplate)

D. Extension functions (add methods to existing classes)

E. Smart casts (no more explicit casting)

F. String templates (no more concatenation)

G. Conditional expressions (if/when)

H. I don't like any of them

Poll Everywhere QR Code or Logo

Text espertus to 22333 if the
URL isn't working for you.

https://pollev.com/espertus

Poll: How do you feel about Java?

Poll Everywhere QR Code or Logo

Text espertus to 22333 if the
URL isn't working for you.

https://pollev.com/espertus

Bonus Slide

Futurama hypnotoad with caption 'ALL HAIL KOTLIN'