Javaにおける「状態を持たない」は「フィールドを持たない」と同じ意味?

こんにちは。ゆうせいです。

プログラミングを学んでいると、「状態を持たないオブジェクト」とか「ステートレスなクラス」という言葉を耳にすることがありますよね。この「状態を持たない」という表現、Javaでは「フィールドを持たない」と言い換えられるのかどうか、今回はそこをじっくり掘り下げていきましょう。


「状態を持たない」ってどういう意味?

まず、「状態」とは何でしょう?

オブジェクト指向において「状態」とは、オブジェクトが内包するデータのことです。Javaで言えば、クラスが持つ**インスタンスフィールド(メンバ変数)**がそれにあたります。

たとえば、こんなクラスがあったとします。

class User {
    String name;
    int age;
}

この User クラスのオブジェクトは、nameage という状態(state)を持っています。


「フィールドを持たない」=「状態を持たない」なのか?

一見すると、インスタンスフィールドがなければ「状態がない」と言いたくなりますが、それは完全には正しくありません

一致する点

確かに、インスタンスフィールドを持たないクラスは「明示的な状態を持たない」といえます。以下のようなクラスはその典型です。

class Utility {
    public static int add(int a, int b) {
        return a + b;
    }
}

このようなクラスは状態を持ちません。なぜなら、フィールドがないからです。そして、すべてのメソッドが static(静的)であるため、インスタンスを作る必要もありません。

こういったクラスは、「状態を持たない(stateless)」とよばれ、並行処理(マルチスレッド)やWeb開発において重要な役割を果たします。


状態はフィールドだけじゃない?

実は、Javaでは状態はフィールド以外にも存在する可能性があります。

例:キャッシュや外部リソース

あるクラスが外部のキャッシュやデータベースにアクセスしており、その情報を使って処理する場合、内部にフィールドがなくても状態を依存しているとみなせることがあります。

class PriceCalculator {
    public int calculate() {
        return ExternalService.getPrice();
    }
}

この PriceCalculator は一見状態を持っていないように見えますが、ExternalService に依存していて、これは暗黙的な状態依存と捉えられることもあるのです。


状態を持たないと何がうれしいのか?

状態を持たない設計には多くの利点があります。

メリット解説
スレッドセーフ状態がないため、同時アクセスでも問題が起きにくい。
テストがしやすい状態に依存しないので、同じ入力に対して常に同じ出力になる。
再利用性が高い汎用的な関数として使い回しが効く。

一方で、デメリットも存在します。

デメリット解説
状態を保持できないロジックが複雑な場合、状態を一時的に保持したいことがある。
必要以上に引数が増える状態を引数で毎回渡す必要があり、コードが読みにくくなることも。

マルチスレッドやWeb開発で「状態を持たない」ことがなぜ重要なのか?

プログラミングで「状態を持たない(stateless)」設計は、マルチスレッド処理Webアプリケーション開発においてとても重要です。でも、なぜそんなに大切なのでしょうか?


まずは前提:マルチスレッドとWeb開発って何?

マルチスレッドとは?

「スレッド」とは、プログラムの中で同時に動く小さな処理の単位のこと。

たとえば、スマホで音楽を聴きながらゲームをして、同時に通知も受け取れる──あの感じに近いです。これを**マルチスレッド(複数のスレッドを同時に動かす)**と呼びます。

Web開発とは?

Webアプリケーションは、ユーザーからのリクエスト(例:ボタンを押す)に対して、サーバーがレスポンス(例:データを返す)を返すしくみで動いています。

そしてこのサーバーでは、多くのユーザーからのリクエストを同時に処理しています。ここでも内部的にはスレッドが大量に並行して処理しているのです。


なぜ「状態を持たない」ことが重要なのか?

理由1:スレッド間でデータの取り合いが起きない

状態(インスタンス変数など)を持つと、複数のスレッドが同じフィールドを読み書きする可能性があります。

class Counter {
    private int count = 0;

    public void increment() {
        count++;
    }
}

このコード、1つの Counter インスタンスを複数のスレッドが使ったらどうなるでしょう?

count の値が不正になる可能性がある!

つまり、競合状態(race condition)が起きるのです。

解決策:

状態を持たなければ、こうした競合は起きません。

public int increment(int value) {
    return value + 1;
}

このように状態を外部から渡すようにすれば、内部でデータを保持しないのでスレッド間の取り合いがなくなります。


理由2:Webアプリケーションは同時アクセスの塊!

Webアプリケーションは、たとえば1秒間に100人が同時にアクセスすることもあります。そのたびに、1つのオブジェクトにデータを保持していたら…どうなると思いますか?

1人のユーザーのデータが、別の人に影響してしまう危険性が出てきます!

例:状態あり vs 状態なし

// 状態あり
class AuthService {
    private String currentUser;

    public void login(String user) {
        this.currentUser = user;
    }

    public String getUser() {
        return this.currentUser;
    }
}

// 状態なし
class StatelessAuthService {
    public String login(String user) {
        return user;
    }
}

前者は「currentUser」が他の人のリクエストにも影響してしまうかもしれませんが、後者は常に独立して動作します。


図で整理してみましょう

状態を持つクラス

+---------+
| Counter |
| count=0 | ← 全スレッドが共有
+---------+

→ 複数スレッドが count を同時に変更してしまう

状態を持たないクラス

+--------------+
| Calculator   |
| add(a, b)    | ← 入力だけで完結
+--------------+

→ 各スレッドが独立して動作。副作用なし。


状態を持たないことで得られる主なメリット

項目説明
スレッドセーフ複数スレッドから同時にアクセスしてもバグにならない
再利用しやすい同じ関数をどこでも使い回せる
テストしやすい同じ入力なら同じ出力になる(予測可能)
拡張しやすい複雑な依存関係を持たない

状態をどう扱うべきか?

実際のアプリケーションでは、完全に状態を排除することは難しい場面もあります。ですが、以下のような設計がよく使われます。

  • 「ロジック部分は状態を持たないクラス(ユーティリティ)に分離」
  • 「状態は Controller や Service レイヤーで最小限に管理」
  • 「必要に応じてスレッドセーフな構造(例:AtomicInteger, ConcurrentHashMap)を使う」

数式でイメージするなら?

状態を持たない関数は、数学的には純粋関数(pure function)として捉えることができます。

たとえば、

f(x) = x + 1

これは入力 x が同じなら、常に同じ結果を返します。これが「状態を持たない」関数の特徴です。

Javaで書けば:

int increment(int x) {
    return x + 1;
}

この関数は、副作用(side effect)も状態も持っていないので、純粋関数=状態を持たない関数といえます。


結論:言い換えは可能だが完全一致ではない

「状態を持たない ≒ フィールドを持たない」とは言えますが、必ずしもイコールではありません

  • 明示的な状態を指す場合:フィールドを持たない = 状態を持たない

セイ・コンサルティング・グループの新人エンジニア研修のメニューへのリンク

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。