Imperative programming expresses computation as commands: create or update state, inspect a condition, repeat work, and return or stop at explicit control-flow points. Code is commonly organized as procedures, methods, or instruction blocks. Its result emerges through mutation, often alongside side effects such as logging, file writes, database updates, network requests, or changes to shared state. section 6.1.1 section 6.1
List<String> result = new ArrayList<>();
for (String word : words) {
if (word.length() > 3) {
result.add(word.toUpperCase());
}
}
This loop tells the machine how to filter and transform words: allocate a result list, inspect every word, test its length, uppercase matching values, and append them. section 6.1.1
The directness is useful when an algorithm depends on heavily mutated state or when a program must perform effects. The cost is that state changes and effects can be hidden from a method signature, making behavior harder to test, reason about, debug, and maintain. Keep necessary impurity explicit rather than disguising it inside an otherwise functional flow. section 6.1.1 section 6.4
One-pass person analysis
An imperative pass can track the youngest and oldest person while collecting names, then sort the names afterward. This is a practical choice when a single traversal and a smaller memory footprint matter; the tradeoff is more branching and higher cognitive complexity than the corresponding stream-based version. section 10.2.2
Choose the style for the constraint, not ideology. Imperative code commonly has less setup overhead for small or simple operations and can suit stateful algorithms. Declarative pipelines can better express transformations and gain composability, lazy evaluation, or parallel processing as data grows, but long pipelines or exception handling may be clearer as imperative code. section 6.4 section 6.5













