Error Handling
Exception Handling
Programming Best Practices
Loops
Code Structure

Should try...catch go inside or outside a loop?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Where you place try...catch around a loop is a behavior decision, not a formatting decision. The correct placement depends on whether one failed item should stop the whole operation or only skip that item. Choosing the wrong scope can either hide serious failures or terminate useful work too early.

Decide Failure Policy First

Before writing code, define policy clearly:

  • Continue processing remaining items if one item fails.
  • Abort the whole loop on first critical failure.

Once policy is explicit, placement becomes straightforward:

  • Catch inside loop for per-item resilience.
  • Catch outside loop for fail-fast all-or-nothing behavior.

Without this decision, teams often mix both patterns and produce inconsistent behavior between modules.

try...catch Inside Loop for Continue-on-Error

This pattern is right for bulk imports, queue consumers, and ETL pipelines where one bad record should not block valid ones.

java
1import java.util.List;
2
3public class ImportJob {
4    public static void processRows(List<String> rows) {
5        for (int i = 0; i < rows.size(); i++) {
6            try {
7                processOne(rows.get(i));
8            } catch (IllegalArgumentException ex) {
9                System.err.println("Row " + i + " skipped: " + ex.getMessage());
10            }
11        }
12    }
13
14    private static void processOne(String value) {
15        if (value == null || value.isBlank()) {
16            throw new IllegalArgumentException("empty value");
17        }
18        System.out.println("Processed: " + value);
19    }
20}

Here the loop keeps progress while preserving diagnostics for failed items.

try...catch Outside Loop for Transaction-Like Behavior

If all items must succeed together, wrap the loop in one block and fail the operation on first error.

java
1import java.util.List;
2
3public class SettlementBatch {
4    public static void run(List<Integer> accountIds) {
5        try {
6            for (Integer id : accountIds) {
7                applySettlement(id);
8            }
9            System.out.println("Batch complete");
10        } catch (RuntimeException ex) {
11            System.err.println("Batch failed: " + ex.getMessage());
12            throw ex;
13        }
14    }
15
16    private static void applySettlement(Integer id) {
17        if (id < 0) {
18            throw new IllegalStateException("invalid account id " + id);
19        }
20    }
21}

This makes fail-fast semantics explicit and compatible with rollback-oriented systems.

Hybrid Pattern with Error Threshold

Some systems need limited tolerance. A hybrid design handles per-item failures but aborts after a threshold.

python
1def process_batch(items, max_errors=3):
2    errors = 0
3
4    for idx, item in enumerate(items):
5        try:
6            process_item(item)
7        except ValueError as exc:
8            errors += 1
9            print(f"item {idx} failed: {exc}")
10            if errors > max_errors:
11                raise RuntimeError("error threshold exceeded") from exc
12
13
14def process_item(item):
15    if item < 0:
16        raise ValueError("negative value")

This is useful when limited data noise is acceptable but systemic failure should stop execution.

Performance Considerations

Exception cost is usually acceptable when errors are rare. Problems appear when exceptions are used as regular control flow inside large loops.

Better pattern for frequent invalid data:

  • Validate cheap conditions first.
  • Reserve exceptions for truly unexpected or exceptional states.

If error frequency is high, redesign to return validation results rather than throwing repeatedly.

Logging and Observability

Regardless of placement, include actionable context in logs:

  • Item index or identifier.
  • Operation stage.
  • Error type.
  • Correlation ID if available.

Context-rich logging helps distinguish isolated bad inputs from widespread system failures.

Testing Strategy

Test both policy branches explicitly:

  • Continue-on-error path with mixed valid and invalid items.
  • Fail-fast path where first error must stop loop.
  • Threshold path where error count triggers abort.

Unit tests should verify not only exceptions but also number of processed records and log events when possible.

Common Pitfalls

  • Catching broad Exception inside loops and silently ignoring critical failures.
  • Using outside-loop catch when business rules require best-effort completion.
  • Using exceptions for expected branching in high-volume loops.
  • Logging errors without item context, making triage slow.
  • Failing to test real error rates and only testing happy-path inputs.

Summary

  • Place try...catch based on explicit failure policy, not coding style.
  • Use inside-loop catch for independent-item resilience.
  • Use outside-loop catch for fail-fast, all-or-nothing operations.
  • Consider threshold-based hybrid handling in noisy data pipelines.
  • Keep error logs contextual and test both success and failure behavior.

Course illustration
Course illustration

All Rights Reserved.