8
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

2.1 Javaプログラムの基本とHello, World!~新Java Basic編 / AI対応版

8
Last updated at Posted at 2023-02-04

はじめに

自己紹介

皆さん、こんにちは、Udemy講師の斉藤賢哉です。私はこれまで、約30年にわたって企業システムの開発に携わってきました。現在も現役のアーキテクトとして、重要システムの技術設計やソリューションの選定を担当しています。直近では、システム開発へのAI適用(AI駆動開発)という全社的な施策でリーダーを務めています。
セミナーでの登壇や雑誌への技術記事の寄稿を行ってきたほか、以下の書籍も執筆しています。

Udemy講座のご紹介

この記事の内容は、私が講師を務めるUdemy講座『新 Java Basic編 / AI対応版』の一部の範囲をカバーしたものです。『新 Java Basic編 / AI対応版』はこちらのリンクから購入できます。

この講座は、以下のような皆様にお薦めします。

  • AIが書いたJavaのコードを読んで、正しさと設計の良し悪しを判断できるようになりたい方
  • 新人のシステムエンジニアとして、Javaの基礎を仕組みから身に付けたい方
  • AIを前提とした開発へ学び直し(リスキリング)をしたい方
  • 「Oracle認定Javaプログラマ」の取得を目指し、Javaの基礎を固めたい方

AIとチャットできるオールインワンの学習環境をリリースしました

Udemy講座の演習を動かすための学習環境として、Windows向けのデスクトップアプリ「Codinable(コーディナブル)」をリリースしました。
エディタ、実行結果、テスト結果、SQL、Webブラウザ、そしてAIチャットを1つの画面にまとめた、オールインワンの学習環境です。

Codinableの画面構成

学習に必要なものは、すべてCodinableの中で完結します。

  • 演習の実行環境(Java 25、Gradle、Bashなど)が一式同梱されており、JDKのインストールや環境変数の設定は不要です
  • インストールして「新規コース開始・再開」からコースを選ぶだけで、講座のすべての演習がそのまま動きます
  • 書き換えて動かなくなっても、「初期化」で配布時の状態に戻せます
  • 開いている演習のファイルと実行結果を踏まえて、AIに質問したり(Askモード)、ファイルの書き換えを指示したり(Agentモード)できます

AIに書き換えを指示し、差分を確かめてから実行する、というAI駆動開発の基本の流れを、Codinableの中だけで安全に体験できます。

AIチャットに書き換えを指示し、差分を確かめて実行する

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プログラム開発の流れ

  • ①開発者がコーディングして、ソースファイル(.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メソッドを持つクラスをメインクラスと呼びます。実行の流れを図で整理します。

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などの文脈依存のキーワードを名前に使っていないか

このチャプターで学んだこと

本チャプターでは、以下を取り上げました。

  1. ソースファイルをjavacでクラスファイルにコンパイルし、javaでJVMの上で実行する仕組みと、コンパイルエラーの読み方
  2. クラスファイルはクラスごとに生成され、クラスパスを起点に検索されること
  3. クラス・メソッド・命令文の入れ子の構造と、JVMがmainメソッドから実行を始める流れ
  4. インデントとブロックの対応、コメントの価値の判断、識別子とキーワードのルールといった、コードを読むための基準
8
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?