はじめに
自己紹介
皆さん、こんにちは、Udemy講師の斉藤賢哉です。私はこれまで、約30年にわたって企業システムの開発に携わってきました。現在も現役のアーキテクトとして、重要システムの技術設計やソリューションの選定を担当しています。直近では、システム開発へのAI適用(AI駆動開発)という全社的な施策でリーダーを務めています。
セミナーでの登壇や雑誌への技術記事の寄稿を行ってきたほか、以下の書籍も執筆しています。
- 「マスタリング Java EE 5」(翔泳社、2007年)
- 「アプリケーションアーキテクチャ設計パターン」(技術評論社、2017年)
- 「Javaエンジニアのためのソフトウェアテスト実践入門」(技術評論社、2024年)
Udemy講座のご紹介
この記事の内容は、私が講師を務めるUdemy講座『新 Java Basic編 / AI対応版』の一部の範囲をカバーしたものです。『新 Java Basic編 / AI対応版』はこちらのリンクから購入できます。
この講座は、以下のような皆様にお薦めします。
- AIが書いたJavaのコードを読んで、正しさと設計の良し悪しを判断できるようになりたい方
- 新人のシステムエンジニアとして、Javaの基礎を仕組みから身に付けたい方
- AIを前提とした開発へ学び直し(リスキリング)をしたい方
- 「Oracle認定Javaプログラマ」の取得を目指し、Javaの基礎を固めたい方
AIとチャットできるオールインワンの学習環境をリリースしました
Udemy講座の演習を動かすための学習環境として、Windows向けのデスクトップアプリ「Codinable(コーディナブル)」をリリースしました。
エディタ、実行結果、テスト結果、SQL、Webブラウザ、そしてAIチャットを1つの画面にまとめた、オールインワンの学習環境です。
学習に必要なものは、すべてCodinableの中で完結します。
- 演習の実行環境(Java 25、Gradle、Bashなど)が一式同梱されており、JDKのインストールや環境変数の設定は不要です
- インストールして「新規コース開始・再開」からコースを選ぶだけで、講座のすべての演習がそのまま動きます
- 書き換えて動かなくなっても、「初期化」で配布時の状態に戻せます
- 開いている演習のファイルと実行結果を踏まえて、AIに質問したり(Askモード)、ファイルの書き換えを指示したり(Agentモード)できます
AIに書き換えを指示し、差分を確かめてから実行する、というAI駆動開発の基本の流れを、Codinableの中だけで安全に体験できます。
AIチャットは、受講者ご自身が生成AIサービス(Anthropic、OpenAI、Googleのいずれか)のAPIキーを登録して使うBYOK(Bring Your Own Key)方式です。利用料金は各社から直接請求されます。APIキーを登録しなくても、AIチャット以外の機能はすべて使えます。
Codinableのインストーラは、以下のGitHubのReleasesページからダウンロードできます(64ビット版のWindows 10/11、管理者権限は不要)。
この記事を含むシリーズ全体像
この記事はJava SEの一部の機能・仕様を取り上げたものですが、一連のシリーズになっており、シリーズ全体でJava SEを網羅しています。また認定資格である「Oracle認定Javaプログラマ」(Silver、Gold)の範囲もカバーしています。シリーズの全体像および「Oracle認定Javaプログラマ」の範囲との対応関係については、以下を参照ください。
2.1 Javaプログラムの基本とHello, World!
チャプターの概要
本チャプターでは、「Hello, World!」と表示する最小のプログラムを題材に、コンパイルと実行の仕組みと、クラス・メソッド・命令文というプログラムの構造を取り上げます。「▶ 実行」がまとめて行う処理をJDKのコマンドに分解し、AIが書いたコードがどの段階で失敗しうるかを判断できるようにします。
2.1.1 コンパイルと実行の仕組み
本レッスンでは、ソースファイルからクラスファイルが作られ、JVMがクラスを見つけて実行するまでの流れを整理します。
ソースファイルから実行まで
Javaのプログラムは、ソースファイル(.java)を作成し、javacコマンドでクラスファイル(.class)にコンパイルし、javaコマンドでJVMの上で実行するという3つの段階で動きます。
- ①開発者がコーディングして、ソースファイル(.java)を作成する
- ②javacコマンドでソースファイルをコンパイルし、クラスファイル(.class)を作る
- ③javaコマンドでクラスファイルを実行する
- クラスファイルは、OSの上のJVMで動作する
本コースではAIが①を、受講者が「▶ 実行」で②と③を行います(チャプター2.2参照)。02_helloのHello.javaを以下に示します。
- 02_hello: Hello
class Hello {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
- ソースファイルの名前は、クラス名に拡張子
.javaを付けたHello.javaである - クラスに
publicを付けた場合は、クラス名とファイル名が一致しないとコンパイルエラーになる(publicの意味はチャプター10.1参照)
JDKのコマンドで動かす場合は、次のように入力します。
$ javac Hello.java
$ java Hello
Hello, World!
-
javacは、成功すると何も表示せずに終了し、同じディレクトリにHello.classを生成する -
javaの引数は、クラスファイル名(Hello.class)ではなくクラス名(Hello)である - Java 11以降は、
java Hello.javaのようにソースファイルを直接指定して、コンパイルと実行をまとめて行うこともできる
コンパイルエラーの読み方
文法や型の誤りがあると、コンパイルは失敗し、クラスファイルは生成されません。文字列を閉じるダブルクォーテーションを忘れた場合のメッセージを以下に示します。
$ javac Hello.java
Hello.java:3: エラー: 文字列リテラルが閉じられていません
System.out.println("Hello, World!);
^
エラー1個
-
Hello.java:3は、エラーがHello.javaの3行目にあることを示す -
^の位置が、コンパイラが問題を検出した箇所を示す - 行番号と位置を手がかりに原因を探すのが、エラー対応の基本である
ソースファイルとクラスファイルの対応
クラスファイルは、原則としてクラスごとに1つ生成されます。ソースファイルとクラスファイルの対応を図で整理します。
- 左に「Hello.java」があり、中に「class Hello」と「class Helper」の2つのクラスが宣言されている
- 中央の「javac」を経て、右に「Hello.class」と「Helper.class」の2つのファイルが生成される
- 下段に「Hello.javaを書き換える」→「再びjavacでコンパイルするまで、Hello.classは古いまま」という流れがある
どのクラスがどのファイルにあるかを分かりやすくするため、「1ソースファイル=1クラス」を原則とします(入れ子クラスはチャプター21.1参照)。
クラスパス
javaコマンドがクラスファイルを探す起点となるパスを、クラスパスと呼びます。検索の流れを図で整理します。
- 左端に「java -cp bin Hello」というコマンドがある
- コマンドから「クラスパス: bin」へ矢印が伸び、さらに「bin/Hello.class」へ矢印が伸びる
- 「bin/Hello.class」が見つかった場合は「JVMがクラスを読み込み、mainメソッドを呼び出す」へ進む
- 見つからない場合は「メインクラスを検出およびロードできないというエラー」へ進む
- 下端に「-cpを指定しない場合は、カレントディレクトリがクラスパスになる」という注記がある
開発の現場では、javacの-dオプションでクラスファイルの出力先を分け、javaの-cp(-classpath)オプションでクラスパスを指定します。
$ javac -d bin src/Hello.java
$ java -cp bin Hello
Hello, World!
Codinableではクラスパスを意識しませんが、ビルドツールやサーバーへの配置の段階では、クラスパスの理解が欠かせません。
レビューの観点
- ソースファイル名が中のクラスの名前を表しているか。
publicでないクラスはファイル名と食い違ってもコンパイルできるため、読み手が迷う名前になっていないか - 1つのソースファイルに、関係の薄い複数のクラスを詰め込んでいないか
- コンパイルエラーのメッセージの行番号と
^の位置を手がかりに、原因の箇所を特定できているか
2.1.2 プログラムの構造
本レッスンでは、クラス・メソッド・命令文の入れ子の構造と、JVMがmainメソッドから実行を始める流れを整理します。
クラス・メソッド・命令文
Javaのプログラムは、必ずクラスの中に記述します。Helloクラスの構造を以下に示します。
- 02_hello: Hello
class Hello { // 【1】
public static void main(String[] args) { // 【2】
System.out.println("Hello, World!"); // 【3】
}
}
- 【1】キーワード
classによって、Helloという名前のクラスを宣言している。クラスの中身は、{から}までの範囲に記述する - 【2】mainメソッドを宣言している。メソッドの中身も
{から}までの範囲に記述する - 【3】コンソールに文字列を表示する命令文である。命令文の末尾には、必ずセミコロン
;を記述する
クラス・メソッド・命令文の入れ子の関係を図で整理します。
- 最も外側の
class Hello { ... }が、クラスである - その内側の
public static void main(String[] args) { ... }が、メソッド(mainメソッド)である -
voidは戻り値の型、mainはメソッド名、String[] argsは引数である - メソッドの中の
System.out.println("Hello, World!");が、命令文である
クラスは、データを表すフィールドと手続きを表すメソッドを持ちます(チャプター7.2参照)。System.out.println()は、ここでは「コンソールに文字列を表示するAPIの呼び出し」と理解しておけば十分です。
mainメソッドから始まる実行
mainメソッドは、プログラムの実行時に最初に呼び出されるメソッドで、mainメソッドを持つクラスをメインクラスと呼びます。実行の流れを図で整理します。
- 上から下へ5つの段階が並ぶ
- ①「java Helloを実行」
- ②「JVMが起動し、Helloクラスを読み込む」
- ③「JVMがmainメソッドを呼び出す」
- ④「mainメソッドの命令文を上から順に実行する」(ここで「Hello, World!」が出力される)
- ⑤「mainメソッドが終わると、プログラムが終了する」
Java 25のコンパクトなソースファイル
Java 25では、クラスの宣言や、mainメソッドのpublic・static・引数を省略できるようになりました(コンパクトなソースファイルとインスタンスmainメソッド)。Java 25の形で書いたHello, World!を以下に示します。
void main() {
IO.println("Hello, World!");
}
- クラスの宣言が無く、mainメソッドに
public、static、引数が無い - 小さなプログラムを簡潔に書くための機能である
開発の現場のコードは従来の形で書かれており、本コースも従来の形を使います(publicとstaticはチャプター10.1と8.1参照)。
レビューの観点
- 起動の入り口(mainメソッド)がどのクラスにあるかが、クラス名やファイルの配置から分かるか
- Java 25より前のシステム向けのコードで、コンパクトなソースファイルの書き方を使っていないか
- mainメソッドに処理を詰め込みすぎず、処理の単位でメソッドやクラスに分けているか
2.1.3 ソースコードの記法と名前
本レッスンでは、ブロックとインデント、コメント、識別子について、AIが書いたコードを読みやすさの観点で判断する基準を整理します。
ブロックとインデント
ブロックとは、{から}で囲まれた範囲です。インデント(字下げ)は動作には影響しませんが、ブロックの入れ子を一目で分かるようにします。その対応を図で整理します。
- 外側から内側へ4段の入れ子の枠が並ぶ
- 最も外側の枠は「クラス」で、インデントは「0単位」
- 2段目の枠は「メソッド」で、「1単位(空白4文字)」
- 3段目の枠は「if文のブロック」で、「2単位(空白8文字)」
- 最も内側は「命令文」で、「3単位(空白12文字)」
- 右側に「インデントの深さ=ブロックの入れ子の深さ」という注記がある
インデントがブロックと食い違っていると、どの命令文がどのブロックに属するかを読み誤ります。なお、命令文の区切りは改行ではなく;で判断されます。
コメント
コメントは、コンパイル時に除外される注釈です。//から行末までの単一行コメント、/*から*/までの複数行コメント、/** */形式のJavadocコメント(チャプター21.4参照)があります。良いコメントと問題のあるコメントを図で比べます。
- 左右2列の比較である
- 左列「良いコメント」: 「なぜこの設計にしたか(意図)」「仕様上の注意点」「
// TODOで残した未対応の作業」 - 右列「問題のあるコメント」: 「コードを読めば分かることの繰り返し(例:
iに1を足す)」「コードと食い違った古い説明」「コメントアウトして残した古いコード」 - 下端に「まず読みやすいコードを書き、コードで表せない意図をコメントで補う」という注記がある
古いコードは、コメントアウトして残すのではなく削除します。過去の状態は、Gitなどのバージョン管理システムで取り出せます。
識別子とキーワード
識別子とは、クラス名や変数名など、プログラムの要素に付ける名前です。英数字、_、$などが使え、数字を1文字目にはできず、大文字と小文字は区別されます。class、intなどの予約語(キーワード)と、true、false、null、_1文字は使えません。var、record、yieldなどの文脈依存のキーワードは、一部の場所では識別子に使えますが、混乱を避けるため使いません。
レビューの観点
- インデントがブロックの入れ子と一致しているか。if文などで
{ }を省略し、インデントだけで構造を表したつもりになっていないか - コメントがコードと食い違っていないか。コードの繰り返しにすぎないコメントや、コメントアウトした古いコードが残っていないか
- 識別子が役割を表す名前になっているか。
varやrecordなどの文脈依存のキーワードを名前に使っていないか
このチャプターで学んだこと
本チャプターでは、以下を取り上げました。
- ソースファイルを
javacでクラスファイルにコンパイルし、javaでJVMの上で実行する仕組みと、コンパイルエラーの読み方 - クラスファイルはクラスごとに生成され、クラスパスを起点に検索されること
- クラス・メソッド・命令文の入れ子の構造と、JVMがmainメソッドから実行を始める流れ
- インデントとブロックの対応、コメントの価値の判断、識別子とキーワードのルールといった、コードを読むための基準








