Java | 基礎文法:early return

Java Java
スポンサーリンク

early return の全体像

early return(早期リターン)は、関数の冒頭で「前提違反・エラー・不要条件」をすぐに判定して、処理を中断し、直ちに戻り値を返す書き方です。深い if/else の入れ子を避けて、主要ロジックを「まっすぐ読める」形にします。目的は可読性を上げ、バグを減らし、意図を明確にすること。ガード節とも呼ばれます。


使い方の基本と効果

ガード節で前提を固定する

入口で不正な入力や状態を弾くと、後続のコードは「前提が満たされている世界」だけを書けばよくなります。否定条件を上側で処理し、肯定の本筋を下側に一直線で置くのがコツです。

int price(int qty) {
    if (qty <= 0) return 0;      // 無効値を早期に処理
    if (qty < 10) return 100 * qty;
    return 90 * qty;             // デフォルト分岐
}
Java

早期リターンを使うと else が減り、分岐の深さが浅く保たれます。読む人は「何を満たせば進むか」を上から順番に理解できます。

入力検証と契約の明確化

メソッドの契約として null 禁止や範囲制約があるなら、最初に検証して即座に止めます。曖昧な状態を内部に持ち込まないのが基本方針です。

import java.util.Objects;

String normalizedUpper(String s) {
    Objects.requireNonNull(s, "s must not be null"); // 契約違反を即座に表面化
    if (s.isBlank()) return "";                      // 早期に既定値へ
    return s.trim().toUpperCase();                   // 本筋
}
Java

重要ポイントの深掘り:ネスト削減と意図の可視化

深い入れ子からの脱出

早期リターンは「否定条件を先に弾く」テクニックです。深い if の中で重ねて判定するより、上から順に振り分けたほうが理解が速くなります。

// Before(読みづらい入れ子)
if (user != null) {
    if (user.isActive()) {
        if (!user.isBanned()) {
            sendMail(user);
        }
    }
}

// After(早期リターンで直線化)
if (user == null) return;
if (!user.isActive()) return;
if (user.isBanned()) return;
sendMail(user);
Java

この形にすると「通過条件のリスト」がそのままコードになり、レビューや修正が容易になります。

早期終了で計算量と副作用を抑える

条件を満たさない場合に即座に抜けることで、無駄な処理を避けられます。複数段の重いチェックは軽いものを先に配置すると、全体効率が上がります。

boolean process(Token token) {
    if (token == null) return false;                 // 軽いチェック
    if (!isValid(token)) return false;               // 中程度
    if (!hasPermission(token)) return false;         // 重いチェック
    doWork(token);
    return true;
}
Java

エラーハンドリング・後始末との組み合わせ

早期リターンと try-finally の両立

後始末が必要な場合は、必ず finally で行います。早期リターンしても finally は実行されるため、安全にクリーンアップできます。

Resource r = acquire();
try {
    if (!r.isReady()) return;    // 早期終了
    use(r);
} finally {
    r.close();                   // 必ず解放
}
Java

リソース管理では try-with-resources を使うと、後始末を自動化しつつ早期リターンも安全に書けます。

try (var br = java.nio.file.Files.newBufferedReader(java.nio.file.Path.of("a.txt"))) {
    String line = br.readLine();
    if (line == null) return;    // 早期終了
    System.out.println(line);
}
Java

よくある疑問と注意点

「return が多いと悪い?」への答え

「どこで戻るかが明確」で「後始末が適切に担保されている」なら、早期リターンはむしろ読みやすさと安全性を高めます。問題になるのは、戻りどころが散らばり過ぎて意図が見えない場合です。入口のガード節に集約し、主要ロジックは一本にすると迷いません。

例外と早期リターンの使い分け

契約違反やプログラムのバグには例外を使い、想定内の条件不成立(空入力、該当なしなど)は早期リターンで扱うと、意図が明確になります。

User findOrNull(String id) {
    if (id == null || id.isBlank()) return null;        // 想定内の不成立
    var user = repository.find(id);
    return user.orElse(null);
}

User findOrThrow(String id) {
    if (id == null || id.isBlank()) throw new IllegalArgumentException("id must not be blank"); // 契約違反
    return repository.find(id).orElseThrow(() -> new IllegalStateException("not found: " + id));
}
Java

例題で身につける

例 1: 早期リターンで入れ子を潰す

int fee(String plan, int qty) {
    if (qty <= 0) return 0;           // ガード
    if (plan == null) return 100 * qty;
    if (plan.equals("PRO")) return 90 * qty;
    return 100 * qty;                 // デフォルト
}
Java

読み手は上から「通過条件」を追えばよく、主要計算が一番下にまとまります。

例 2: バリデーションを入口で終わらせる

int taxed(int subtotal, double rate) {
    if (subtotal < 0) throw new IllegalArgumentException("subtotal must be >= 0");
    if (rate < 0 || rate > 1) throw new IllegalArgumentException("rate must be 0..1");
    return (int) Math.round(subtotal * (1 + rate));  // 本筋
}
Java

契約違反は即時に止め、主要計算から「防御コード」を追い出します。

例 3: 早期リターンと try-with-resources

import java.nio.file.*;
import java.io.*;

String firstLineOrEmpty(Path p) throws IOException {
    try (var br = Files.newBufferedReader(p)) {
        String line = br.readLine();
        if (line == null || line.isBlank()) return "";  // 早期終了+既定値
        return line.trim();
    }
}
Java

後始末は自動、分岐は冒頭で終了させて本筋を短く保っています。


仕上げのアドバイス(重要部分のまとめ)

early return は「否定条件を入口で弾き、主要ロジックを一本化」するための設計技法です。ガード節で前提を固定し、else を減らして直線化する。重い処理は軽いチェックの後に置き、不要な計算を早期に避ける。リソース管理では finally や try-with-resourcesと組み合わせて安全に終了させる。例外は契約違反に、早期リターンは想定内の不成立に——この使い分けが身につけば、コードは読みやすく、変更にも強くなります。

タイトルとURLをコピーしました