Java | Java 詳細・モダン文法:設計・実務視点 – 公開 API の互換性

Java Java
スポンサーリンク

公開 API の互換性とは何か

公開 API の互換性とは、
「一度公開した API を、後から変更しても利用者のコードが壊れないようにすること」
です。

ここでいう「利用者」は、
あなたのクラスを呼び出す別のクラスかもしれないし、
別チームのモジュールかもしれないし、
外部の顧客システムかもしれません。

公開 API の互換性は、実務の Java 開発において
最も重要な設計観点の一つ です。
なぜなら、API を壊すと「利用者のコードがコンパイルできない」「本番で動かなくなる」など、
大きな事故につながるからです。


互換性には種類がある

ソース互換性(Source Compatibility)

利用者の ソースコードがコンパイルできるか に関わる互換性です。

例えば、メソッド名を変えるとソース互換性が壊れます。

// 旧 API
void save(User user);

// 新 API(互換性が壊れる)
void store(User user);
Java

呼び出し側は save() を呼んでいるので、コンパイルエラーになります。

バイナリ互換性(Binary Compatibility)

利用者が 再コンパイルしなくても動くか に関わる互換性です。

Java はバイナリ互換性を強く重視しており、
例えば「メソッドを追加する」だけならバイナリ互換性は壊れません。

// 旧 API
class UserService {
    void save(User user) {}
}

// 新 API(互換性は壊れない)
class UserService {
    void save(User user) {}
    void delete(User user) {} // 追加は OK
}
Java

利用者は save() だけを呼んでいれば、再コンパイルなしで動きます。

振る舞い互換性(Behavior Compatibility)

動作が変わらないか に関わる互換性です。

例えば、同じ入力に対して返す値が変わると、
ソースもバイナリも壊れていなくても、利用者の期待を裏切ります。

// 旧 API
int calculateFee(int price) {
    return price / 10;
}

// 新 API(互換性が壊れる)
int calculateFee(int price) {
    return price / 5; // 振る舞いが変わった
}
Java

これは実務で最も危険な互換性破壊です。


互換性を壊す変更と壊さない変更

互換性を壊す代表例(絶対に慎重に扱う)

  • メソッド名の変更
  • 引数の型・数の変更
  • 戻り値の型変更
  • public フィールドの削除
  • クラス名の変更
  • 例外の追加(チェック例外)
  • メソッドの削除

これらは利用者のコードを即座に壊します。

互換性を壊さない代表例(安全な変更)

  • メソッドの追加
  • private メソッドの変更
  • クラス内部のリファクタリング
  • Optional を返すメソッドの追加
  • default メソッドの追加(インターフェース)

特に Java 8 以降の default メソッド は、
インターフェースの後方互換性を保つための強力な仕組みです。


互換性を守るための API 設計テクニック

パラメータオブジェクトを使う

// 悪い例:将来の拡張に弱い
void createUser(String name, int age);

// 良い例:拡張に強い
record CreateUserRequest(String name, int age) {}

void createUser(CreateUserRequest request);
Java

フィールドを追加しても API は壊れません。

Optional を返す(null を返さない)

// 悪い例
User find(String id); // null の可能性

// 良い例
Optional<User> find(String id);
Java

戻り値の意味が明確になり、互換性も保ちやすくなります。

インターフェースは default メソッドで拡張する

interface UserRepository {
    User find(String id);

    default List<User> findAll() {
        throw new UnsupportedOperationException();
    }
}
Java

既存の実装クラスを壊さずに API を拡張できます。

例外はむやみに追加しない

チェック例外を追加すると、
利用者のコードがコンパイルエラーになります。

// 悪い例
void save(User user) throws IOException; // 後から追加すると壊れる
Java

実務で最も重要な観点:API は「一度公開したら簡単に変えられない」

公開 API は“契約”である

API は「利用者との契約」です。
契約を破ると、利用者のコードが壊れます。

だからこそ、
公開 API は慎重に設計し、むやみに変更しない
という姿勢が必要です。

内部 API と公開 API を分ける

実務では、
「外部に見せる API(public)」と
「内部で使う API(package-private / private)」
を明確に分けることが重要です。

内部 API は自由に変えてよいですが、
公開 API は互換性を守る必要があります。


初心者が意識すべきポイント

  • public を安易に付けない
  • null を返さない
  • メソッドの削除・変更は慎重に
  • default メソッドやパラメータオブジェクトで拡張性を確保
  • 振る舞いを変えるときは必ず影響範囲を確認

これだけで、API の互換性事故は大幅に減ります。


まとめ:公開 API の互換性を自分の言葉で説明するなら

あなたの言葉で整理すると、こうなります。

「公開 API の互換性とは、
一度公開した API を変更しても利用者のコードが壊れないようにすること。
ソース互換性・バイナリ互換性・振る舞い互換性の三つがあり、
特に振る舞いの変更は最も危険。

メソッド名変更・引数変更・戻り値変更・削除は互換性を壊すため慎重に扱い、
default メソッド、パラメータオブジェクト、Optional などを使って
将来の拡張に強い API を設計することが重要。」

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