Javaの開発や運用において、実行時に突然java.lang.UnsupportedClassVersionErrorが発生し、プログラムが停止してしまうことがあります。

このエラーは、Javaの実行環境(JRE/JVM)と、プログラムがビルドされた際のコンパイラ(JDK)のバージョンが一致していないことを示しています。

特に近年ではJavaのリリースサイクルが早まり、プロジェクトごとに異なるLTS(Long Term Support)バージョンを使い分ける機会が増えたため、このエラーに直面するエンジニアが増えています。

本記事では、このエラーが発生する根本的なメカニズムから、具体的な確認方法、そして開発環境やビルドツールにおける解決策までを詳しく解説します。

java.lang.UnsupportedClassVersionErrorとは何か

java.lang.UnsupportedClassVersionErrorは、Java仮想マシン(JVM)がクラスファイルをロードしようとした際に、そのクラスファイルのバージョンがJVMのサポートしているバージョンよりも新しい場合にスローされるエラーです。

Javaのプログラムは、ソースコード(.javaファイル)をコンパイルしてバイトコード(.classファイル)に変換します。

このクラスファイルの中には「メジャーバージョン」と呼ばれる数値が記録されており、JVMはこの数値を参照して、自分が実行可能な形式かどうかを判断します。

JVMには「自分より古いバージョンでコンパイルされたファイルは実行できるが、自分より新しいバージョンでコンパイルされたファイルは実行できない」という後方互換性の原則があります。

したがって、例えばJDK 21でコンパイルされたクラスファイルを、Java 17のランタイムで実行しようとすると、このエラーが発生します。

逆に、Java 11でコンパイルされたものをJava 21で動かすことは問題ありません。

エラーメッセージの読み解き方

エラーが発生した際、コンソールには以下のようなメッセージが表示されることが一般的です。

java.lang.UnsupportedClassVersionError: com/example/Main has been compiled by a more recent version of the Java Runtime (class file version 65.0), this version of the Java Runtime only recognizes class file versions up to 61.0

このメッセージには解決のための重要なヒントが隠されています。

  • class file version 65.0:これはクラスファイルがJava 21でコンパイルされたことを示しています。
  • only recognizes class file versions up to 61.0:これは現在の実行環境がJava 17までしか対応していないことを示しています。

このように、エラーメッセージに表示される数値をJavaのバージョンに変換することで、どのバージョンの不一致が起きているかを正確に把握できます。

Javaバージョンとクラスファイルバージョンの対応表

Javaのメジャーバージョンと、それに対応するクラスファイルのバージョン番号の対応は以下の通りです。

トラブルシューティングの際の参照用として活用してください。

Javaバージョンクラスファイル形式(メジャーバージョン)
Java SE 2367
Java SE 2266
Java SE 21 (LTS)65
Java SE 2064
Java SE 1963
Java SE 1862
Java SE 17 (LTS)61
Java SE 11 (LTS)55
Java SE 8 (LTS)52
Java SE 751

注意点として、Java 8以降は「メジャーバージョン = Javaバージョン + 44」という計算式で求めることができます。

例えば、Java 21であれば 21 + 44 = 65 となります。

エラーが発生する主な原因

このエラーが発生するシナリオは、主に以下の3つのパターンに集約されます。

1. 環境変数の設定ミス

開発機に複数のJDKをインストールしている場合、コンパイル時に使用する javac のパスと、実行時に使用する java コマンドのパスが異なるバージョンのJDK/JREを指していることがあります。

例えば、PATH 環境変数の優先順位により、コンパイルは最新のJDKで行われ、実行は古いOS標準のJavaで行われるといったケースです。

2. IDE(統合開発環境)の設定不備

IntelliJ IDEAやEclipse、Visual Studio CodeなどのIDEでは、プロジェクトごとに「プロジェクトSDK」や「言語レベル」を設定します。

プロジェクトのビルド設定では高いバージョンを指定しているにもかかわらず、IDE内で設定されている実行用JREが古い場合にエラーが発生します。

3. ビルドツールと実行環境の乖離

MavenやGradleを使用してビルドを行い、成果物(JARファイルなど)をサーバーへデプロイした際に発生します。

ビルドサーバー(CI/CD)では最新のJDKを使用しているが、デプロイ先のデリバリー環境や本番サーバーのJavaバージョンが古いまま更新されていないという状況です。

具体的な解決策と修正手順

原因を特定したら、以下の手順で修正を行います。

状況に合わせて最適な方法を選択してください。

手順1:現在のバージョンを確認する

まずは、現在使用しているコンパイラとランタイムのバージョンをターミナル(コマンドプロンプト)で確認します。

Shell
# コンパイラのバージョン確認
javac -version

# 実行環境のバージョン確認
java -version

もし javac が 21.x.x で、 java が 17.x.x であれば、実行環境をアップグレードするか、コンパイルターゲットを下げる必要があります。

手順2:実行環境(JRE/JDK)をアップグレードする

最も推奨される解決策は、実行環境をコンパイル環境と同じか、それ以上のバージョンに合わせることです。

Windowsの場合、JAVA_HOME 環境変数を新しいJDKのインストールディレクトリに変更し、PATH 変数の先頭に %JAVA_HOME%\bin を追加します。

macOSやLinuxの場合は、sdkman などのバージョン管理ツールを使用すると切り替えがスムーズです。

Shell
# SDKMAN! を使用した例
sdk install java 21.0.2-tem
sdk use java 21.0.2-tem

手順3:コンパイル時のターゲットバージョンを下げる

実行環境のバージョンを上げられない事情がある場合(古いサーバーでの運用など)、コンパイル時に出力されるクラスファイルのバージョンを下げることができます。

javacコマンドを使用する場合

--release オプション(Java 9以降)を使用します。

Shell
# Java 17互換のクラスファイルを作成する
javac --release 17 Main.java

Mavenを使用する場合

pom.xmlmaven-compiler-plugin 設定を修正します。

XML
<project>
    <properties>
        <maven.compiler.release>17</maven.compiler.release>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <!-- ターゲットとなるバージョンを指定 -->
                    <release>17</release> 
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Gradleを使用する場合

build.gradle に以下の設定を追加します。

gradle
java {
    // ターゲットバージョンを指定
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

手順4:IDEの設定を見直す(IntelliJ IDEAの例)

IDEを使用している場合は、以下の設定箇所が一致しているか確認してください。

Project Structure > Project

SDKLanguage level が一致しているか。

Settings > Build, Execution, Deployment > Compiler > Java Compiler

各モジュールの Target bytecode version が適切か。

Run/Debug Configurations

実行時に使用される JRE が正しいか。

動作確認用のサンプルプログラム

実際にエラーを発生させ、解決を確認するための簡単なコードを紹介します。

Java
// Main.java
public class Main {
    public static void main(String[] args) {
        // Java 21の新しい文字列メソッドなどを使ってみる
        String message = "  Hello, Java Version Check!  ";
        System.out.println(message.strip()); 
        
        // ランタイムのバージョンを表示
        System.out.println("Runtime Version: " + System.getProperty("java.version"));
    }
}

このファイルをJDK 21でコンパイルし、Java 17で実行するとエラーが再現されます。

Shell
# JDK 21でコンパイル
/path/to/jdk-21/bin/javac Main.java

# Java 17で実行(エラー発生)
/path/to/jdk-17/bin/java Main

出力結果(エラー時):

実行結果
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.UnsupportedClassVersionError: Main has been compiled by a more recent version of the Java Runtime (class file version 65.0), this version of the Java Runtime only recognizes class file versions up to 61.0

次に、ターゲットを指定してコンパイルし直します。

Shell
# ターゲットを17に指定してコンパイル
javac --release 17 Main.java

# 再度Java 17で実行(成功)
/path/to/jdk-17/bin/java Main

出力結果(成功時):

実行結果
Hello, Java Version Check!
Runtime Version: 17.0.x

再発を防止するためのベストプラクティス

このエラーを未然に防ぐために、以下の運用ルールを導入することを検討してください。

Dockerによる環境の固定化

開発環境、CI環境、本番環境をすべて同じDockerイメージベースで構築することで、Javaバージョンの不一致を完全に排除できます。

Dockerfile 内でベースイメージ(例:eclipse-temurin:21-jdk)を指定すれば、環境差異による問題は発生しません。

ビルドツールのToolchains機能の活用

MavenやGradleには「Toolchains」という機能があります。

これを利用すると、ローカルの環境変数に依存せず、ビルドスクリプト内で定義された特定のJDKバージョンを自動的にダウンロード・使用してビルドを行うことができます。

.java-version ファイルの設置

sdkmanasdf などのツールを利用している場合、プロジェクトのルートに .java-version ファイルを置いておくと、ディレクトリを移動するだけで自動的にJavaバージョンが切り替わります。

まとめ

java.lang.UnsupportedClassVersionError は、一見複雑に見えるかもしれませんが、その本質は「コンパイル時よりも古いJavaで実行しようとしている」という単純な不一致です。

解決のためには、まずエラーメッセージに含まれるクラスファイルバージョン(65.0、61.0など)を確認し、どのバージョンの差分があるかを特定しましょう。

その上で、実行環境をアップデートするか、ビルド時のターゲットバージョンを適切に設定することで解決が可能です。

特にクラウドネイティブな開発が主流となっている現代では、CI/CDパイプラインやコンテナオーケストレーションにおけるJavaバージョンの管理が重要です。

本記事で紹介した対応表や設定方法を活用し、スムーズなトラブルシューティングと安定したアプリケーション運用を実現してください。