Sheet ⁨09⁩ · ⁨Quizzes⁩Surveyed ⁨2026⁩

Kotlin: Modern JVM Language Fundamentals

14 QuestionsIntermediatePublished: Updated:

Kotlin: Modern JVM Language Fundamentals

Up to 20 questions, shuffled on every run

Quiz Configuration
Enterto start

Kotlin reads like a friendlier Java for about a week, and then you meet the parts that are genuinely different: nullability living in the type system, coroutines with a scope that owns its children, and extension functions that look like methods but do not dispatch like them.

This quiz targets those. Most questions are about a distinction that compiles either way, which is what makes them worth knowing: the wrong choice does not fail, it quietly does something else.

Nullability is a type split, which is why the compiler can refuse member access and then smart cast inside a null check. Below, what a coroutine scope guarantees: no child outlives it, and one failure cancels the siblings.

Several questions are really about production behaviour rather than syntax, and one in particular is worth seeing laid out, because it is where the coroutine model meets a blocking JDBC driver.

`suspend` lets a function release its thread, but a blocking call has no suspension point, so it holds one. On a dispatcher sized to one thread per core, a handful of concurrent JDBC queries starves everything else.

Read the explanations even on the ones you get right. Most name the specific failure mode rather than restating the answer, and the failure mode is the reason the distinction exists at all.

Answer key and explanations14 questions

The quiz above draws 14 questions at random from these 14, so a second attempt will not be the same run. Everything in the pool is listed here.

  1. Why does `s.length` fail to compile when `s` is declared as `String?`

    Answer`String?` is a different type from `String`, and the compiler will not allow member access until null is handled

    Nullability is part of the type. `String` and `String?` are distinct types, and the compiler refuses any member access on the nullable one until you have handled the null case. That is what makes Kotlin null safety a compile-time guarantee rather than a convention, and it is why `?.`, `?:` and smart casts exist.

  2. What does `!!` actually do?

    AnswerAsserts the value is non-null, throwing a KotlinNullPointerException if it is not

    It asserts non-null and throws `KotlinNullPointerException` if the value is null. Its legitimate use is narrow: you know something the compiler cannot prove and you would rather crash than proceed. Using it to silence a compile error throws away the guarantee the type system was giving you, and turns a compile-time error into a production crash.

  3. What is a platform type, written `String!` in IDE hints?

    AnswerA type from Java with unknown nullability, which Kotlin neither enforces nor rejects

    A type coming from Java where nullability is unknown. The compiler cannot prove it is non-null and will not force you to treat it as nullable, so it trusts you. This is the main route by which NullPointerExceptions still enter a Kotlin codebase, and the fix is to annotate the Java side or wrap the boundary in a nullable Kotlin type immediately.

  4. Which members does `data class User(val id: String, val name: String)` generate?

    Answerequals, hashCode, toString, copy, and componentN, from the constructor properties only

    The compiler generates `equals`, `hashCode`, `toString`, `copy` and `componentN` functions for destructuring. They are derived only from properties declared in the primary constructor. A property declared in the class body is excluded from equals and copy, which produces two objects that compare equal despite differing state.

  5. What is the difference between `val` and `const val`?

    Answer`const val` is a compile-time constant inlined at use sites; `val` is assigned at runtime

    `val` is a read-only reference assigned once at runtime, so it can be initialised from a function call. `const val` is a compile-time constant, must be a primitive or String, must be top level or in an object, and is inlined at every use site. Inlining matters for library authors: changing a `const val` requires recompiling consumers.

  6. What does `coroutineScope { }` guarantee that plain `launch` on a global scope does not?

    AnswerIt waits for all children, and cancels the siblings if one fails

    It will not return until every child coroutine has completed, and if any child fails it cancels the remaining siblings and rethrows to the caller. That is structured concurrency: work cannot outlive the scope that started it, and a failure cannot be silently orphaned. `GlobalScope.launch` gives you neither, which is why it is discouraged outside application-lifetime tasks.

  7. How do `launch` and `async` differ in how an exception surfaces?

    Answer`launch` propagates immediately; `async` holds the exception until `await()` is called

    `launch` returns a `Job` and propagates an exception to the parent scope as soon as it happens. `async` returns a `Deferred` and holds the exception until you call `await()`. So a failing `async` that is never awaited can appear to do nothing until the surrounding scope cancels, which is the most misunderstood behaviour in the coroutines API.

  8. Does marking a function `suspend` make a blocking JDBC call non-blocking?

    AnswerNo. Wrap it in withContext(Dispatchers.IO), or use a non-blocking driver

    No. `suspend` allows a function to pause and release its thread at suspension points, but a blocking call has no suspension point: it holds the thread until it returns. On `Dispatchers.Default`, sized to roughly one thread per core, a few concurrent blocking queries starve every other coroutine on that dispatcher. Wrap it in `withContext(Dispatchers.IO)`, whose pool is elastic, or use a non-blocking driver.

  9. What is the difference between `apply` and `let`?

    Answer`apply` returns the receiver; `let` returns the lambda result

    `apply` runs a block with the object as `this` and returns the object, so it is for configuring something. `let` passes the object as `it` and returns the block result, so it is for transforming. Choosing wrong compiles fine and returns the wrong value, which makes it a quiet bug. `also` is `apply` with `it`; `run` is `let` with `this`.

  10. What does a `sealed` class give you that an abstract class does not?

    AnswerA closed set of subclasses, so `when` can be checked for exhaustiveness without an else

    The set of direct subclasses is known at compile time and restricted to the same module and package, so the compiler can verify a `when` covers every case. That makes the `else` branch unnecessary, and it means adding a new subclass turns every exhaustive `when` into a compile error rather than a silent fallthrough. It is the mechanism behind modelling results and states safely.

  11. How is an extension function dispatched?

    AnswerStatically, by the declared type; it is compiled to a static method and cannot be overridden

    Statically, based on the declared type of the expression, because an extension is compiled to a static method taking the receiver as its first parameter. It is not a member of the class and cannot be overridden. So if a base and a derived type both have an extension of the same name, the one chosen depends on the declared type of the variable, not the runtime object.

  12. What is `lateinit var` for, and what is its main limitation?

    AnswerDeferring initialisation of a non-null property; it cannot be used with primitives and throws if read too early

    It defers initialisation of a non-null property so you do not need a nullable type or a dummy value, which suits dependency injection and test setup. It cannot be used with primitive types, it must be a `var`, and reading it before assignment throws `UninitializedPropertyAccessException`. `by lazy` is the better tool when the value can be computed on first access.

  13. Why does an `object` declaration differ from a class with a companion object?

    AnswerAn `object` is a standalone singleton; a companion object is a singleton belonging to a class

    An `object` declaration is a singleton: the declaration and the sole instance are the same thing, initialised lazily and thread-safely on first access. A companion object is a singleton *attached to* a class, giving it something like static members while still being a real object that can implement interfaces. Use `object` for a standalone singleton, a companion for factory methods and constants belonging to a type.

  14. What does `@JvmStatic` change when Kotlin code is called from Java?

    AnswerIt emits a real static method, so Java can call it without going through `Companion`

    It generates a genuine static method so Java can call `MyClass.create()` instead of `MyClass.Companion.create()`. Without it the companion is a real object and Java must go through the `Companion` field. This is one of a family of interop annotations, alongside `@JvmOverloads` for default arguments and `@JvmName` for renaming, which exist because Kotlin features have no direct Java equivalent.

Was this useful?

You might also enjoy

More posts on similar topics

Java: Core Language & JVM Fundamentals

Java: Core Language & JVM Fundamentals

Java has quietly powered banks, Android, and countless backend systems for decades, and the language keeps evolving with records, sealed classes, and virtual threads. This quiz walks through the core

PHP & Laravel: Modern Web Development Fundamentals

PHP & Laravel: Modern Web Development Fundamentals

Ready to check how well you know PHP and Laravel? This quiz runs through routing and middleware, Eloquent relationships and the N+1 trap, migrations and seeders, Blade, and the artisan workflow. Read

C# & .NET: Language and Runtime Fundamentals

C# & .NET: Language and Runtime Fundamentals

Ready to test how well you know C# and the .NET runtime? This quiz walks through the type system, LINQ, async/await, the CLR and garbage collection, and modern features like records and pattern matchi

Rust: Ownership, Borrowing & Memory Safety

Rust: Ownership, Borrowing & Memory Safety

This quiz tests your grip on the parts of Rust that trip up newcomers and pay off later: ownership and moves, borrowing and lifetimes, traits and generics, pattern matching, error handling with `Resul

TypeScript Advanced: Types, Generics, Utility Types

TypeScript Advanced: Types, Generics, Utility Types

Welcome to the TypeScript Advanced Quiz! Test your knowledge on advanced types, generics, utility types, and more. Each question has a hint and explanations for all options. Good luck!

WebAssembly (WASM): Performance & Interoperability

WebAssembly (WASM): Performance & Interoperability

Welcome to the WebAssembly (WASM) Quiz! This quiz will test your knowledge of WebAssembly concepts, performance benefits, and practical use cases. Each question is designed to challenge your understan

6 related posts