What is the benefit of the typed form tasks.named<JavaCompile>('compileJava') over the untyped tasks.named('compileJava'), and what happens if the type is wrong?
answer
- typed named<T> → TaskProvider<T>
- no cast, IDE completion
- runtime type assertion at realization
- wrong type → failure on resolve
- use when task type is known
basics
~10 sThe typed form returns a TaskProvider<JavaCompile>, giving statically-typed access to JavaCompile properties inside the block — no cast needed. If the actual task isn't that type, Gradle fails when the task is realized.
solid answer
~40 s`tasks.named("compileJava")` returns a `TaskProvider<Task>`, so inside the configuration block you only see the generic `Task` API — to touch `options.encoding` you'd need a cast. The typed overload `tasks.named<JavaCompile>("compileJava")` returns a `TaskProvider<JavaCompile>`, so the block is typed as `JavaCompile` and you get direct, compile-checked access to its properties (in Kotlin DSL, full IDE completion). The type argument is also a **runtime assertion**: if the task named `compileJava` is not assignable to `JavaCompile`, Gradle throws (an `InvalidUserDataException`/`UnknownTaskException`-style failure) when it resolves the provider. So the typed form buys you both ergonomics and a sanity check. Use it whenever you know the task's type, which is almost always for well-known tasks like `compileJava`, `test`, or `jar`.
code
kotlin · 9 lines// Typed: direct JavaCompile access
tasks.named<JavaCompile>("compileJava") {
options.encoding = "UTF-8"
}
// Untyped: would need a cast to reach options
tasks.named("compileJava") {
(this as JavaCompile).options.encoding = "UTF-8"
}go deeper
Know that named<JavaCompile>() lets you set JavaCompile properties without casting.
Explain that the type is both a typed receiver and a runtime assertion at realization.
Discuss choosing typed vs untyped based on known type and base-Task-only configuration cases.
Encourage typed accessors across conventions for safer, self-documenting build logic at scale.
## Untyped vs typed named() `tasks.named("compileJava")` → `TaskProvider<Task>`. The configuration block sees the base `Task` interface. To configure `JavaCompile`-specific state you must cast: `(this as JavaCompile).options...`, which is verbose and unsafe. `tasks.named<JavaCompile>("compileJava")` (Kotlin) / `tasks.named("compileJava", JavaCompile)` (Groovy) → `TaskProvider<JavaCompile>`. The block is typed as `JavaCompile`: ```kotlin tasks.named<JavaCompile>("compileJava") { options.encoding = "UTF-8" // JavaCompile.options — no cast options.compilerArgs.add("-Xlint:all") } ``` In the Kotlin DSL this also gives full static type-checking and IDE autocompletion on the receiver. ## The type argument is a runtime check too The generic type is not merely a compile-time hint. When Gradle resolves the provider (realizes the task), it verifies the actual task type is assignable to the requested type. If you wrote `tasks.named<Jar>("compileJava")`, resolution fails because `compileJava` is a `JavaCompile`, not a `Jar`. This catches mistakes early rather than producing a `ClassCastException` deep in a block. ## When to use which Prefer the typed form whenever you know the type — virtually all built-in tasks (`test` → `Test`, `jar` → `Jar`, `compileJava` → `JavaCompile`). Fall back to untyped `named()` only when the type is genuinely unknown or you only need base `Task` properties (e.g. `group`, `description`, `dependsOn`). ## Relationship to withType `withType<T>()` is the bulk analogue: it selects *all* tasks of a type. `named<T>(name)` selects *one* task and asserts its type. Both deliver typed configuration receivers and both are lazy. ## Summary - Typed `named<T>` → `TaskProvider<T>`, typed block, no cast, IDE completion. - Also a runtime type assertion at realization. - Untyped `named` → only base `Task` API.
- What happens if you call tasks.named<Jar>('compileJava')?Gradle fails when resolving the provider because compileJava is a JavaCompile, not assignable to Jar — a type mismatch caught at realization rather than a deep ClassCastException.
- Is the typed form lazy like the untyped one?Yes — both return a lazy TaskProvider; the type argument adds typing/assertion but does not change laziness.
saying these in an interview costs you the question
- Saying the type argument is purely cosmetic with no runtime effect.
- Believing untyped named() gives access to subtype-specific properties without a cast.