skip to content

Command in Java

Runnable and Callable are command objects: a request packaged as an object and handed to an executor to run later, elsewhere, or on a schedule. Interviewers connect this to the executor framework and to why Callable exists alongside Runnable.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

5

What is the Command design pattern, and how do Java's Runnable and Callable embody it?

level: juniorimportance: must knowfreq 70%

answer

  1. Encapsulate a request as an object
  2. Runnable = run(), no result; Callable = call(), returns V + throws
  3. Executor is the invoker that consumes commands
  4. Decouples caller from when/where work runs

basics

~20 s

The Command pattern wraps a request as an object so you can pass it around, store it, and run it later. In Java, Runnable and Callable are command objects: each bundles a piece of work in one method (run or call) that something else executes when it chooses.

solid answer

~40 s

The Command pattern turns a request or action into a standalone object, decoupling the code that asks for work from the code that performs it. The object carries everything needed to do the job, so it can be passed, queued, logged, or deferred. Java realizes this with Runnable (a no-argument, no-result task whose work lives in run()) and Callable<V> (a task that returns a value of type V and may throw a checked exception, in call()). You hand these command objects to an executor, which decides when and on which thread to invoke them. This separation is exactly the Command pattern's intent: the caller does not know how or when the action runs, only that it is encapsulated and submittable.

go deeper

for a junior

Can state that Command wraps a request as an object and that Runnable/Callable are those objects handed to something that runs them later.

for a middle

Explains the Runnable-vs-Callable difference (result + checked exception) and that the ExecutorService is the invoker that decouples submission from execution.

for a senior

Maps the four classic roles (command/invoker/receiver/client) onto Java types and explains why object-ification unlocks queueing, scheduling, pooling, and result retrieval via Future.

for a principal

Frames Command as the conceptual backbone of the java.util.concurrent design — tasks as values enable backpressure, scheduling policies, and composition — and can discuss trade-offs versus direct invocation in API design.

## The problem the Command pattern solves Normally, when you want some code to run, you call a method directly: `service.doWork()`. The caller and the work are tightly bound together in time and place — the work runs *now*, on *this* thread, and the caller must know the exact method to call. Sometimes that is too rigid. You may want to: run the work *later*, run it on a *different thread*, put many pieces of work in a *queue*, *undo* it, *log* it, or *retry* it. To do any of that, the request itself must become a thing you can hold in a variable — an **object**. That is the **Command pattern**: *encapsulate a request as an object*, so the request can be stored, passed around, and executed by code that knows nothing about what the request actually does. ### The roles in the classic pattern - **Command**: an interface with a single method (often `execute()`). Concrete commands implement it. - **Invoker**: holds and triggers commands but does not know their contents (e.g. a button, a scheduler, a queue). - **Receiver**: the object the command actually operates on. - **Client**: creates the command and configures it. ## How Java embodies it: Runnable and Callable Java's standard library ships two ready-made Command interfaces: - **`Runnable`** — a *functional interface* (one abstract method) with the method `void run()`. It takes no arguments, returns nothing, and cannot throw checked exceptions. It is the simplest command: "do this work." - **`Callable<V>`** — a functional interface with the method `V call() throws Exception`. Unlike Runnable, it **returns a result** of type `V` and **may throw a checked exception**. It is the command for work that produces a value. Both are **command objects**: each instance bundles one unit of work. Because they are functional interfaces, you can create them with a lambda or method reference: ```java Runnable r = () -> System.out.println("hello"); Callable<Integer> c = () -> 2 + 2; ``` ## The invoker: the executor framework In modern Java, the **invoker** is usually an `ExecutorService` (an *executor*). You **submit** a command to it and the executor decides *when* and *on which thread* to run it. It may run it immediately, queue it, schedule it for later, or hand it to a pool of worker threads: ```java ExecutorService pool = Executors.newFixedThreadPool(4); pool.execute(r); // runs a Runnable, returns nothing Future<Integer> f = pool.submit(c); // runs a Callable, returns a Future for the result ``` This is the Command pattern in full: the executor (invoker) consumes encapsulated requests (Runnable/Callable) without knowing what they do. The caller is decoupled from *how, when, and where* the work runs. ## Why this matters Because the request is an object, the framework can do things impossible with a direct method call: pool threads, queue overflow work, schedule with a delay, retry, or collect results via `Future`. The encapsulation is what unlocks all of that. ## Key terms defined - **Functional interface**: an interface with exactly one abstract method, so it can be implemented by a lambda. - **Executor / ExecutorService**: an object that runs submitted tasks, abstracting away thread management. - **Future<V>**: a handle representing the eventual result of a Callable; you call `get()` to retrieve it (blocking until ready). - **Checked exception**: an exception the compiler forces you to declare or handle; Callable can throw these, Runnable cannot.

  • Why can a lambda be used wherever a Runnable or Callable is expected?
    Both are functional interfaces (a single abstract method), so a lambda or method reference whose shape matches that method is a valid implementation. The compiler infers the target type from context.
  • Name another classic Command pattern capability that Java's executor framework provides.
    Queueing: submitted tasks can wait in the executor's work queue until a thread is free, and ScheduledExecutorService can defer or repeat them — both rely on the request being a stored object.

saying these in an interview costs you the question

  • Saying Runnable returns a value (it does not; only Callable does)
  • Claiming the Command pattern is about threads — threading is just one use; the pattern is request-as-object
  • Thinking calling run() directly is the 'pattern' — without an invoker/executor there is no decoupling

context

open as a page

When submitting tasks to an ExecutorService, how do execute(Runnable) and submit(...) differ, and what does submit return?

level: middleimportance: must knowfreq 68%

basics

~20 s

execute(Runnable) just runs the task and returns nothing. submit(...) accepts a Runnable or Callable and returns a Future you can use to wait for completion, get a Callable's result, or cancel the task. submit also captures exceptions inside the Future instead of letting them escape.

open as a page

How does the executor framework let Command objects be deferred, queued, or scheduled, and which executor supports delayed/periodic execution?

level: middleimportance: should knowfreq 52%

basics

~20 s

Because tasks are objects, an executor can hold them in a queue and run them when a thread is free (deferred/queued). For time-based running, ScheduledExecutorService lets you schedule a task to run after a delay or repeatedly at a fixed rate or fixed delay.

open as a page

When a ThreadPoolExecutor's queue and pool are full, what happens to a submitted Command, and how is that behavior controlled?

level: seniorimportance: should knowfreq 38%

basics

~20 s

If all threads are busy and the work queue is full, the executor can't accept the task, so it applies a rejection policy. The default policy throws RejectedExecutionException. You can choose other policies, like running the task on the caller's thread or silently discarding it.

open as a page

How do Java's Runnable/Callable + executors compare to the textbook Command pattern, and which classic capabilities (like undo) do they not directly provide?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Runnable and Callable are command objects and executors are the invoker, so they cover the core Command pattern: requests become objects you can queue, defer, and run elsewhere. But the textbook pattern often adds undo/redo and explicit receivers; Runnable has only one execute-style method, so undo and history aren't built in — you'd add them yourself.

open as a page