skip to content

What is the difference between a generic parameter `<T>` and `<T : Any>`? When would you use the `Any` upper bound?

level: seniorimportance: should knowfreq 45%

answer

  1. <T> means <T : Any?>
  2. <T : Any> bans nullable type args
  3. Non-null T inside the body
  4. Use for keys / fail-fast / no-null APIs
  5. Multiple bounds via where clause

basics

~20 s

A plain <T> actually means <T : Any?>, so T may be nullable. Writing <T : Any> forces T to be a non-null type, banning String? and friends — useful when null would break your logic.

solid answer

~50 s

An unconstrained type parameter `<T>` has the implicit upper bound `Any?`, so a caller may bind `T = String?`, and inside the function `T` can be null. Declaring `<T : Any>` raises the bound to the non-null root `Any`, so callers can only supply non-null types; `null` becomes a compile error at the call site and `T` is treated as non-null inside. Use the `Any` bound when null is meaningless or dangerous — e.g. map keys, builders that must produce a value, or APIs that should reject null early rather than NPE later. It also lets you call `.hashCode()`/`.toString()` without null checks and return `T` (non-null) confidently. Contrast `<T : Any>` (non-null) with `<T>` / `<T : Any?>` (nullable allowed); the difference is purely about whether the bound's bottom of nullability is `Any` or `Any?`.

code

kotlin · 3 lines
kotlin
fun <T : Any> requirePresent(value: T?): T = value ?: error("required")
// caller cannot bind T to a nullable type argument
val name: String = requirePresent("Ada")

go deeper

for a junior

Recognizes <T : Any> forbids null where plain <T> allows it.

for a middle

Knows the implicit bound is Any? and that the non-null bound changes call-site and body behavior.

for a senior

Chooses the bound deliberately for keys/fail-fast APIs and combines bounds with where.

for a principal

Designs library generics around nullability contracts and Java-interop platform types, balancing strictness vs ergonomics.

## Implicit bound Every type parameter has an **upper bound**. If you write nothing, Kotlin uses `Any?`: ```kotlin fun <T> identity(x: T): T = x // T : Any? -> nullable allowed identity<String?>(null) // OK: T = String? ``` Because the bound is `Any?`, `T` can be a nullable type, and inside the function the compiler must treat `x` as possibly null. ## Non-null bound with `Any` ```kotlin fun <T : Any> firstNonNull(items: List<T?>): T = items.firstOrNull { it != null } ?: error("none") fun <T : Any> store(key: T) { /* key can't be null */ } // store<String?>(null) // ERROR: upper bound is Any, not Any? ``` With `<T : Any>`: - Callers cannot bind `T` to a nullable type. - Inside, `T` is non-null, so you can call `key.hashCode()`, `key.toString()` and return a `T` without `?` handling. ## When to use the `Any` bound - **Keys / identity:** map keys, set elements, cache keys — null keys are usually illegal or surprising. - **"Must produce a value" APIs:** factories/builders where returning null defeats the purpose. - **Fail-fast contracts:** reject null at compile time instead of risking an NPE deep in the call. - **Bridging Java:** when you want to forbid the platform-null that Java interop can smuggle in. ## Relationship to the lattice This is the practical payoff of the `Any` vs `Any?` distinction in the type lattice: the *default* generic bound is the **top** (`Any?`), and choosing `Any` deliberately drops nullability from the allowed set. It is *not* about a specific class hierarchy — both are 'accept anything', the only difference is whether null is in. ## Note on multiple bounds For several bounds use a `where` clause: `fun <T> f(x: T) where T : Any, T : Comparable<T>`. Here `T : Any` still contributes the non-null requirement.

  • Inside `fun <T> f(x: T)`, can the compiler assume `x` is non-null?
    No. The implicit bound is `Any?`, so `x` may be null; you must null-check. Add `<T : Any>` to make `x` non-null.
  • How do you require both non-null AND `Comparable`?
    Use a `where` clause: `fun <T> f(x: T) where T : Any, T : Comparable<T>`. The `T : Any` clause supplies non-nullability.

saying these in an interview costs you the question

  • Thinking plain `<T>` forbids null
  • Believing `<T : Any>` restricts to a specific class hierarchy
  • Not knowing the default bound is `Any?`
  • Using `!!` inside `<T : Any>` code unnecessarily
  • Confusing upper bound with variance (`out`/`in`)

context