はじめに (対象読者・この記象でわかること)

この記事は、Javaでアプリケーションを開発しているが「パッケージ名に日付を入れたら突然コンパイルエラーになった」という経験のある中級者以上の開発者向けです。特に、マイグレーションツールやバッチ処理で「yyyy.mmdd」形式のパッケージを切ってしまった方は必見です。
この記事を読むことで、Javaの識別子(identifier)にまつわる厳密な仕様、パッケージ名に使える文字と使えない文字、そして「数字で始まるパッケージ」がダメな理由を正確に理解できます。さらに、既存コードをリネームせずにビルドを通すための回避策(Maven/Gradleの設定、IDEのリファクタリング手順)も実践形式で紹介します。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。 - Java の基礎文法(パッケージ宣言の書き方) - コンソールまたは IDE でのコンパイルができること - Maven または Gradle を使ったビルド経験(バージョン管理の話が出てきます)

Java の「識別子」ルールがパッケージ名にまで適用される理由

Java でパッケージ名を決めるとき、多くの開発者は「とりあえず小文字+ドット区切り」で運用しています。しかし、言語仕様(JLS §3.8)を厳密に読むと、パッケージ名は「識別子の連結」として扱われるため、識別子で許可されていない文字・並びが混入するとコンパイル時点で error: <identifier> expectederror: not a statement が出てしまいます。
代表的にハマるのが「数字で始まる部分」です。たとえば com.example.2025 というパッケージを作ると、2025 は識別子として不合法なため、結果的に com.example.2025 全体が無効と見なされます。
「でも、JavaScript や Python では数字フォルダも普通に使えるのに…」と思うかもしれません。Java は元々「識別子=将来的にクラス名や変数名にも流用可能」という設計思想があるため、パッケージ名も厳格なルールが適用されるのです。

日付をパッケージ名に使ったらどうなる?実例で見るハマリ方と回避テクニック

ステップ1:問題の再現 ── 日付パッケージを切ってコンパイル

  1. 適当な Maven プロジェクトを作ります。
    bash mvn archetype:generate -DgroupId=com.example -DartifactId=demo -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false cd demo

  2. 日付パッケージを作ってクラスを置く
    ```bash mkdir -p src/main/java/com/example/20250625 cat > src/main/java/com/example/20250625/DailyJob.java <<'EOF' package com.example.20250625; // ← ココが問題

public class DailyJob { public static void main(String[] args) { System.out.println("Hello 20250625"); } } EOF ```

  1. ビルド
    bash mvn compile 以下のエラーが出力されます。
    /Users/xxx/demo/src/main/java/com/example/20250625/DailyJob.java:1: error: <identifier> expected package com.example.20250625; ^

ステップ2:JLS を読んで原因を特定

Java 言語仕様(JLS 17 §3.8)では、識別子を

Identifier:
  IdentifierChars but not a Keyword, BooleanLiteral, or NullLiteral

と定義し、さらに IdentifierChars は数字で開始してはならないと明記されています。
20250625 は数字で始まるため、識別子として不合法。したがってパッケージ名としても不合法、というわけです。

ハマりどころ

  • 「フォルダ名(ディレクトリ名)は作れたのに、なぜビルドで死ぬの?」
    → ファイルシステムは数字フォルダを拒まないが、Java コンパイラは言語仕様に従って拒否する。
  • 「他の言語では普通に使えるのに…」
    → Java はパッケージ名を将来的にクラス名や変数名にマッピングできるように設計されているため。
  • 「過去のプロジェクトで動いていたのに!」
    → 古い Eclipse コンパイラ(ecj)は緩く判定していた時代があるが、javac や新しい ecj は厳格。

解決策

1. パッケージ名をリネームする(最も推奨)

Maven のリネームプラグインで一括置換

Bash
# 1. バックアップ git add -A && git commit -m "before rename" # 2. 一括置換(日付をアンダースコア付きに) find src -type d -name '20250625' | xargs -I{} mv {} _20250625 find src -type f -name '*.java' | xargs sed -i '' 's/20250625/_20250625/g'

2. ビルドのみを通す姑息な回避(非推奨)

javac に -source 8 -target 8 を明示しても、識別子ルールは緩和されない。
よって「リネームせずにビルドを通す」方法は存在しません。パッケージ名を変えるか、上位パッケージを切り替えるしかありません。

3. IDE リファクタリングを使う(IntelliJ IDEA 例)

  1. プロジェクトツリーで 20250625 フォルダを右クリック → Refactor → Rename
  2. 「Rename package」を選び、新しい名前を _20250625 にして Refactor
  3. 「Search in comments and strings」もチェックして、コード内の参照を一括置換
  4. ビルド実行(⌘F9)で success が出ることを確認

まとめ

本記事では、Java でパッケージ名に日付を使ったことが原因でコンパイルエラーになる仕組みを解説しました。

  • Java の識別子ルールはパッケージ名にも適用され、数字で始まる部分は不合法
  • ファイルシステム上は作れても、javac が受理しないため「ビルドだけ突然失敗する」という現象が起きる
  • リネームする以外にビルドを通す方法はなく、Maven/Gradle/IDE のリファクタリング機能で安全に移行できる

この記事を通して、パッケージ命名で「とりあえず日付でいいや」と開き直らないよう、言語仕様を意識した設計の重要性を伝えられれば幸いです。
次回は「アンダースコア2つ(__)で始まるパッケージが運用で問題になるケース」について掘り下げる予定です。

参考資料

  • Java Language Specification, Java SE 17 Edition §3.8 Identifiers
    https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html#jls-Identifier
  • Maven Compiler Plugin – デフォルト設定とエラーケース
    https://maven.apache.org/plugins/maven-compiler-plugin/
  • IntelliJ IDEA Help – Rename Refactorings
    https://www.jetbrains.com/help/idea/rename-refactorings.html
  • 日本Javaユーザグループ プログラミング言語Java 公式ページ(JLS 和訳リンク集)
    https://www.java-users.jp/