Runnable as a Functional Interface
Fast recall
Quick revision
Core answer
Runnable is a functional interface whose single abstract method is void run(). A no-argument, void-compatible lambda can target it, such as () -> doWork(). An expression statement may be void-compatible even if the called method returns a value, because that value can be ignored. Captured local variables must be final or effectively final.Connection between multithreading concepts and Java 8 functional programming features, showing breadth of knowledge
Not recognizing Runnable as a functional interface or not knowing that method references also work as Runnable implementations
Demonstrate a lambda and method reference as Runnable, and mention the at-FunctionalInterface annotation validates this contract
Interview-ready guide
Interview answer
Runnable is a functional interface, which means it has exactly one abstract method, the run method.
Since Java 8, functional interfaces can be implemented with lambda expressions or method references, which makes concurrent code much more concise. Before Java 8, passing a task to a thread meant writing new Runnable with an anonymous class and overriding run. Now you just use a lambda: empty parentheses, an arrow, then the body.
Method references work too. If a method takes no parameters and returns void, you can pass it directly as a Runnable using the double colon syntax. This shows up everywhere in production code.
When you submit tasks to an executor, you'll see lambdas all the time. The key insight is that Runnable's signature, no parameters and void return, matches what a no-arg lambda produces. One gotcha to mention: a lambda can only read variables that are effectively final, so capturing a loop counter directly fails to compile.
You copy it into a final local first. The at-FunctionalInterface annotation keeps Runnable a single-method interface.
Runnable as a Functional Interface
Direct Answer
Runnable is a functional interface whose single abstract method is void run(). A no-argument, void-compatible lambda can target it, such as () -> doWork(). An expression statement may be void-compatible even if the called method returns a value, because that value can be ignored. Captured local variables must be final or effectively final.
Common Mistakes & Pitfalls
- Not knowing method references work: Writing
() -> this.doWork()whenthis::doWorkis cleaner—any no-arg void method is a validRunnable. - Capturing mutable variables: Lambdas can only read effectively final variables.
() -> count++on a mutablecountwon't compile—useAtomicIntegeror rethink the design. - Capturing a loop variable: The loop counter isn't effectively final; copy it into a final local before capturing.
- Overusing lambdas: Stuffing heavy business logic into a lambda makes it unreadable and untestable—use a class.
Check your understanding
Answer these without looking back at the article.
- What makes an interface a functional interface?
- What is @FunctionalInterface annotation?
- Can a Callable be replaced by a lambda?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.