Return to site

☕🧡 JAVA & KOTLIN: SYNTAX SIDE-BY-SIDE (NOT A WAR 😄)

· java,kotlin,programmmer,techlead

Kotlin often looks “shorter”, but modern Java (records, virtual threads…) has caught up in many ways. Here’s a quick tour of 4 syntax differences you’ll actually meet in real projects 👇

🔸 TL;DR

▪️ Kotlin gives you batteries-included syntax (properties, by lazy, null-safety, coroutines).

▪️ Modern Java answers with records and virtual threads, reducing the gap without changing the language too much.

▪️ Don’t pick a side based on memes 😅 — understand how each feature maps to real-world code & maintenance.

Section image

🔸 PROPERTY CONSTRUCTOR VS JAVA RECORDS

Kotlin:

data class User(val id: Long, val name: String)

Old-school Java:

class User {

private final long id;

private final String name;

// constructor + getters + equals/hashCode/toString…

}

Modern Java with records 🧾:

public record User(long id, String name) {}

▪️ Kotlin’s primary constructor + data class is still ultra concise.

▪️ Java records now cover the same use case for immutable data carriers.

🔸 DELEGATION & LAZY INITIALIZATION

Kotlin:

val config: Config by lazy {

loadConfigFromRemote()

}

Java (one common pattern):

private volatile Config config;

public Config config() {

if (config == null) {

synchronized (this) {

if (config == null) {

config = loadConfigFromRemote();

}

}

}

return config;

}

▪️ Kotlin’s by lazy {} gives you thread-safe lazy init with one keyword.

▪️ In Java, you usually rely on patterns (double-checked locking, suppliers, frameworks) instead of language-level delegation.

🔸 JAVA if VS KOTLIN ?. OPERATOR (NULL-SAFETY)

Kotlin:

val city = user?.address?.city ?: "Unknown"

Java:

String city = "Unknown";

if (user != null && user.getAddress() != null) {

city = user.getAddress().getCity();

}

▪️ Kotlin’s ?. and ?: encode null-safety in the type system and syntax.

▪️ In Java, you express the same intent with explicit checks, Optional, or libraries.

🔸 COROUTINES VS VIRTUAL THREADS

Kotlin:

suspend fun fetchAll() = coroutineScope {

val a = async { callServiceA() }

val b = async { callServiceB() }

a.await() to b.await()

}

Modern Java (virtual threads) 💡:

try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {

Future〈 String〉 a = executor.submit(this::callServiceA);

Future〈 String〉 b = executor.submit(this::callServiceB);

return a.get() + " " + b.get();

}

▪️ Kotlin coroutines = language-level async, structured concurrency, suspend functions.

▪️ Java virtual threads = cheap threads with familiar blocking style (no new async API to learn).

🔸 TAKEAWAYS

▪️ Syntax is strategy: Kotlin focuses on brevity & expressiveness; Java on stability & backward compatibility.

▪️ With records + virtual threads, Java feels much more “modern” than its stereotypes.

▪️ You don’t need to be “Team Java” or “Team Kotlin” — better be “Team Understand Both” and pick the right tool for the context 🤝

#Java #Kotlin #Java21 #VirtualThreads #Coroutines #CleanCode #Backend #JVM #SoftwareEngineering #Learning

Go further with Java certification:

Java👇

Spring👇

SpringBook👇