『入門向け』Java開発環境の構築とかんたんなコードの書き方と実行方法 (中編)
はじめに
この記事は、 rubytomato.hateblo.jp に続く記事の中編です。 前編ではJava開発環境の構築とEclipseの簡単な使い方を中心に説明しました。この記事ではJavaプログラムの書き方と実行方法を中心に説明します。
Javaプログラムの書き方
前編のおさらい
前編でどこまでおこなったか簡単におさらいをしておきます。
まず、Eclipse(Pleiades All in One Eclipse
)のセットアップとFig1のようにstudy01project
プロジェクトとDemo
クラスまで作成しました。
つぎにレッスン1のはじめで
まで説明しました。
レッスン1(つづき)
レッスン1のつづきでは、Eclipseを使ったJavaプログラムの書き方をもう少し踏み込んで説明したいと思います。
このレッスンでは、おかしの情報を扱うSnack
というクラスを題材に、クラス、フィールド、コンストラクタ―の定義方法を説明します。
Snackクラスを作成する
まずcom.example.lesson01.model
パッケージを作成し、model
パッケージにSnack
クラスを作成します。
パッケージおよびクラスの作成方法が分からない場合は前編の記事をご覧ください。
Fig2はmodel
パッケージおよびSnack
クラスを作成した直後のプロジェクトの状態です。
以下がSnack
クラスを作成した直後のソースコードです。
package com.example.lesson01.model; public class Snack { }
フィールドを定義する
Snack
クラスに、おかしの名前を持つname
、値段を持つprice
、原材料を持つingredients
の3つのフィールドを定義します。
name
とprice
は必須のフィールドで、ingredients
は情報があればセットするというオプショナルなフィールドというルールにします。
package com.example.lesson01.model; public class Snack { /** * 名前 (必須) */ private String name; /** * 値段 (必須) */ private int price; /** * 原材料 (任意) */ private String ingredients; }
アクセサメソッドを実装する
定義したフィールドのアクセサメソッドを定義します。アクセサメソッドとはフィールドのゲッターや、セッターメソッドのことです。
たとえばname
フィールドであれば、name
フィールドの値を取得するgetName
メソッドがゲッターメソッド、値をセットするsetName
メソッドがセッターメソッドです。
メソッドの先頭にget
やset
が付くことからゲッター(getter)・セッター(setter)メソッドと呼ばれています。
以下のコードはname
フィールドのアクセサメソッドの例です。
// 名前フィールドのゲッター public String getName() { return name; } // 名前フィールドのセッター public void setName(String name) { this.name = name; }
アクセサメソッドは、手動でコーディングするのは非効率なのでEclipseの機能を使って自動的に生成するようにします。生成は下記のメニューバーかキーボードのショートカットから行えます。
- メニューバーの
ソース(S)
→getter および setter の生成(R)...
を選択 - キーボードのShift + Alt + Sを押しメニューの
getter および setter の生成(R)...
を選択
"getter および setter の生成"画面(Fig4)でフィールドをすべて選択し、"生成"ボタンをクリックします。
以下がゲッター・セッターが生成された状態のソースコードです。
package com.example.lesson01.model; public class Snack { /** * 名前 (必須) */ private String name; /** * 値段 (必須) */ private int price; /** * 原材料 (任意) */ private String ingredients; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public String getIngredients() { return ingredients; } public void setIngredients(String ingredients) { this.ingredients = ingredients; } }
Snackクラスのオブジェクトを生成する
Demo
クラスを開き、mainメソッドにSnack umaibou = new Snack();
というコードを追加します。
public static void main(String[] args) { System.out.println("Lession01 Demo start"); // サラミ味のおかしを生成 Snack umaibou = new Snack(); System.out.println("Lession01 Demo end"); }
するとFig5のようにSnack
の部分に赤い下線が表示されると思います。これはSnack
クラスのインポート文がコーディングされていないために起きているエラーです。
インポート文を追加するために、赤い下線の部分にカーソルを置きCtrl + 1を押し、メニューからSnack をインポートします (com.example.lesson01.model)
というメニューを選択します。これでインポート文が追加されエラーは解消します。
Snack umaibou = new Snack();
というコードでは、変数の宣言とコンストラクターの呼び出しを行っています。
このコードによりumaibou
というSnack
型の変数に、Snack
クラスのオブジェクトが代入されます。
Snack umaibou = new Snack();
^^^^^ ^^^^^^^ ^^^ ^^^^^^^
| | | |
| | | +--- コンストラクター名
| | |
| | +------- newキーワードでコンストラクタ―を呼び出す
| |
| +----------------- 変数名
|
+----------------------- 変数の型
オブジェクトのフィールドに値をセットする
オブジェクトを生成したらセッターメソッドを使ってオブジェクトのフィールドに値をセットします。
このときにEclipseのコード補完を使うとタイピング量が減り且つ正確にコードがかけます。
umaibou.
とまでタイプするとFig7のようにコード補完の候補が表示されます。候補が表示されない場合はCtrl + Spaceを押してください。
セッターメソッドの候補だけを表示するには、さらにumaibou.set
とまでタイプします。そうするとset
から始まるメソッドやフィールドだけが候補になるので選択が楽になります。この中から選択するとそのコードで補完されます。
以下が3つのフィールド(name
, price
, ingredients
)をセットするソースコードです。
// サラミ味のおかしを生成 Snack umaibou = new Snack(); umaibou.setName("うまいぼう サラミ味"); umaibou.setPrice(10); umaibou.setIngredients("コーン,植物油脂,糖類,ポークパウダー,香辛料,パン粉,ビーフパウダー,酵母エキスパウダー,パセリ,調味料,香料,甘味料,カラメル色素,酸化防止剤");
オブジェクトの情報を出力する
ここまででオブジェクトを生成しフィールドの値をセットするコードがかけましたので、そのオブジェクトの情報をコンソールへ出力してみたいと思います。
コンソールへ出力するにはSystem.out.println
を使います。以下のコードを追加しファイルを保存します。
System.out.println("name=" + umaibou.getName() + " price=" + umaibou.getPrice() + " ingredients=" + umaibou.getIngredients());
ここまでコーディングしたmainメソッドの全体を示します。
public static void main(String[] args) { System.out.println("Lession01 Demo start"); // サラミ味のおかしを生成 Snack umaibou = new Snack(); umaibou.setName("うまいぼう サラミ味"); umaibou.setPrice(10); umaibou.setIngredients("コーン,植物油脂,糖類,ポークパウダー,香辛料,パン粉,ビーフパウダー,酵母エキスパウダー,パセリ,調味料,香料,甘味料,カラメル色素,酸化防止剤"); System.out.println("name=" + umaibou.getName() + " price=" + umaibou.getPrice() + " ingredients=" + umaibou.getIngredients()); System.out.println("Lession01 Demo end"); }
Demo
クラスのmainメソッドを実行し、コンソールに以下の内容が出力されると成功です。これでオブジェクトの情報を表す文字列をコンソールに出力することができました。
Lession01 Demo start name=うまいぼう サラミ味 price=10 ingredients=コーン,植物油脂,糖類,ポークパウダー,香辛料,パン粉,ビーフパウダー,酵母エキスパウダー,パセリ,調味料,香料,甘味料,カラメル色素,酸化防止剤 Lession01 Demo end
次にもう1つ新しいおかしを追加します。これまでと同じようにオブジェクトを生成し、セッターメソッドでフィールドに値をセットします。
// チーズ味のおかしを生成 Snack umaibouCheese = new Snack(); umaibouCheese.setName("うまいぼう チーズ味"); umaibouCheese.setPrice(10); umaibouCheese.setIngredients("コーン,植物油脂,チーズパウダー,乳糖,クリーミングパウダー,乳製品,パン粉,砂糖,食塩,香辛料,調味料,香料,パプリカ色素,甘味料,ph調整剤,乳化剤,ターメリック色素");
おなじように、このオブジェクトの情報を出力するコードも加えます。
System.out.println("name=" + umaibouCheese.getName() + " price=" + umaibouCheese.getPrice() + " ingredients=" + umaibouCheese.getIngredients());
ここまでコーディングしたmainメソッドの全体を示します。
public static void main(String[] args) { System.out.println("Lession01 Demo start"); // サラミ味のおかしを生成 Snack umaibou = new Snack(); umaibou.setName("うまいぼう サラミ味"); umaibou.setPrice(10); umaibou.setIngredients("コーン,植物油脂,糖類,ポークパウダー,香辛料,パン粉,ビーフパウダー,酵母エキスパウダー,パセリ,調味料,香料,甘味料,カラメル色素,酸化防止剤"); // チーズ味のおかしを生成 Snack umaibouCheese = new Snack(); umaibouCheese.setName("うまいぼう チーズ味"); umaibouCheese.setPrice(10); umaibouCheese.setIngredients("コーン,植物油脂,チーズパウダー,乳糖,クリーミングパウダー,乳製品,パン粉,砂糖,食塩,香辛料,調味料,香料,パプリカ色素,甘味料,ph調整剤,乳化剤,ターメリック色素"); System.out.println("name=" + umaibou.getName() + " price=" + umaibou.getPrice() + " ingredients=" + umaibou.getIngredients()); System.out.println("name=" + umaibouCheese.getName() + " price=" + umaibouCheese.getPrice() + " ingredients=" + umaibouCheese.getIngredients()); System.out.println("Lession01 Demo end"); }
Demo
クラスのmainメソッドを実行して、以下のようにコンソールに2つのおかしの情報が出力されれば成功です。
Lession01 Demo start name=うまいぼう サラミ味 price=10 ingredients=コーン,植物油脂,糖類,ポークパウダー,香辛料,パン粉,ビーフパウダー,酵母エキスパウダー,パセリ,調味料,香料,甘味料,カラメル色素,酸化防止剤 name=うまいぼう チーズ味 price=10 ingredients=コーン,植物油脂,チーズパウダー,乳糖,クリーミングパウダー,乳製品,パン粉,砂糖,食塩,香辛料,調味料,香料,パプリカ色素,甘味料,ph調整剤,乳化剤,ターメリック色素 Lession01 Demo end
オブジェクトの情報を出力するのにtoStringメソッドを利用する
toStringメソッドはオブジェクトの情報を文字列にして返すメソッドです。このメソッドはjava.lang.Object
クラスというすべてのクラスのスーパークラスで定義されているので、どのクラスでも使用できます。
このメソッドを使ってオブジェクトの情報を出力するように修正します。以下の2行を
System.out.println("name=" + umaibou.getName() + " price=" + umaibou.getPrice() + " ingredients=" + umaibou.getIngredients()); System.out.println("name=" + umaibouCheese.getName() + " price=" + umaibouCheese.getPrice() + " ingredients=" + umaibouCheese.getIngredients());
以下のように書き換えます。
System.out.println(umaibou.toString()); System.out.println(umaibouCheese.toString());
修正してファイルを保存したらDemo
クラスのmainメソッドを実行してみます。真ん中の2行がumaibouとumaibouCheeseをtoStringメソッドで出力した結果です。修正前に比べると人間にはよくわからない文字列が出力されるようになってしまったと思います。
Lession01 Demo start com.example.lesson01.model.Snack@1d251891 com.example.lesson01.model.Snack@48140564 Lession01 Demo end
toStringメソッドをオーバーライドする
実はjava.lang.Object
クラスのtoStringメソッドのデフォルトの実装では、人間にとって意味のある(人間が読める)情報を出力しないため、Snack
クラスで改めてtoStringメソッドをオーバーライドする必要があります。
オーバーライドとは、すでに実装されているメソッドより、新しいメソッドを優先させることです。
Snack
クラスのtoStringメソッドをオーバーライドするためにSnack.javaをエディタで開きます。
ちなみに、Demo
クラスのソースコード上のSnackにカーソルを置いた状態でF3を押すか、Ctrlを押しながらマウスカーソルをSnackにあわせて、メニューの宣言を開く
を選択すると、Snack.javaのソースコードが開きます。
toStringメソッドをオーバーライドするコードは、これまでと同様にEclipseの機能を使って自動的に生成する方が効率がよく正確です。 生成は下記のメニューバーかキーボードのショートカットの操作から行えます。カーソルは生成するコードを出力したい場所へおいてください。
- メニューバーの
ソース(S)
→toString() 生成(R)...
を選択 - キーボードのShift + Alt + Sを押しメニューの
toString() 生成(R)...
を選択
"toString() 生成"画面(Fig10)が表示されるので出力するフィールドを選択します。ここでは3つすべて選択し"生成"ボタンをクリックします。
すると、以下のコードが追加されたと思います。@Override
という記述はアノテーションといって、このtoStringメソッドがSnack
クラスでオーバーライドされていることを表しています。
@Override public String toString() { return "Snack [name=" + name + ", price=" + price + ", ingredients=" + ingredients + "]"; }
ソースコードを保存したら、もう一度Demo
クラスのmainメソッドを実行してみます。コンソールに以下のように出力されれば成功です。
Lession01 Demo start Snack [name=うまいぼう サラミ味, price=10, ingredients=コーン,植物油脂,糖類,ポークパウダー,香辛料,パン粉,ビーフパウダー,酵母エキスパウダー,パセリ,調味料,香料,甘味料,カラメル色素,酸化防止剤] Snack [name=うまいぼう チーズ味, price=10, ingredients=コーン,植物油脂,チーズパウダー,乳糖,クリーミングパウダー,乳製品,パン粉,砂糖,食塩,香辛料,調味料,香料,パプリカ色素,甘味料,ph調整剤,乳化剤,ターメリック色素] Lession01 Demo end
変数名を変える
これまでのコードを見てみると、サラミ味のおかしの変数の名前はumaibou
、チーズ味のおかしの変数の名前はumaibouCheese
となっています。
サラミ味の変数名が少し抽象的なので、umaibouSalami
に変えたいと思います。
変数名を変えるのも手動で1行ずつ変更していくのではなく、Eclipseの機能を使った方が簡単で正確です。変更する変数名にカーソルをあわせておいた状態で、下記のメニューバーかキーボードのショートカットの操作から行えます。
- メニューバーの
リファクタリング(T)
→名前の変更(N)...
を選択 - キーボードのShift + Alt + Rを押す
するとエディタ上でカーソルがリファクタリングモードになりますので、変数名を変えてEnterを押して確定させます。
コンストラクタを実装する
さらにめんたい味のおかしを追加してみます。
// めんたい味のおかしを生成 Snack umaibouMentai = new Snack(); umaibouMentai.setName("うまいぼう めんたい味"); umaibouMentai.setIngredients("コーン,植物油脂,糖類,パプリカ,香辛料,パン粉,たん白加水分解物,たら調味パウダー,食塩,調味料,香料,パプリカ色素,甘味料");
めんたい味のおかしのオブジェクト情報を出力するコードも書きます。
System.out.println(umaibouMentai.toString());
Demo
クラスのmainメソッドを実行するとコンソールにめんたい味のおかしの情報が出力されたと思いますが、price
フィールドは0
となっています。これはオブジェクト生成後にセッターでpriceフィールドを初期化しなかったためです。フィールドの値は明示的に初期化しないとデフォルト値で初期化されます。price
フィールドの値が0で出力されたのはint型の初期値が0であるためです。
Snack [name=うまいぼう めんたい味, price=0, ingredients=コーン,植物油脂,糖類,パプリカ,香辛料,パン粉,たん白加水分解物,たら調味パウダー,食塩,調味料,香料,パプリカ色素,甘味料]
例えば、プログラムの仕様(ルール)で、name
、price
フィールドは必ずセットしなければならないと決められていた場合、このコードはバグにあたります。このバグは以下のようにprice
フィールドに値をセットするコードを追加すること対応できますが、これよりもっと適切な対応方法があります。
// めんたい味のおかしを生成 Snack umaibouMentai = new Snack(); umaibouMentai.setName("うまいぼう めんたい味"); umaibouMentai.setPrice(10); // この行を追加してバグ修正する umaibouMentai.setIngredients("コーン,植物油脂,糖類,パプリカ,香辛料,パン粉,たん白加水分解物,たら調味パウダー,食塩,調味料,香料,パプリカ色素,甘味料");
引数と取るコンストラクターを実装する
オブジェクト生成後に個別にセッターで値をセットするのではなく引数を取るコンストラクターを実装して初期化するようにします。
エディタでSnack.javaを開きコンストラクターを実装しますが、これもEclipseの機能を使って自動的に生成します。生成は下記のメニューバーかキーボードのショートカットの操作から行えます。カーソルは生成するコードを出力したい場所へ置いてください。
- メニューバーの
ソース(S)
→フィールドを使用してコンストラクタ―を生成(A)...
を選択 - キーボードのShift + Alt + Sを押しメニューの
フィールドを使用してコンストラクタ―を生成(A)...
を選
"フィールドを使用してコンストラクタ―を生成"画面(Fig12)で、初期化するフィールドにname
とprice
を選択し"生成"ボタンをクリックします。
下記が生成されたコンストラクタ―のコードです。コンストラクターはメソッドのように見えますが戻り値が無いことと、コンストラクタ―名がクラス名と同じでなければならないという特徴があります。
public Snack(String name, int price) { super(); this.name = name; this.price = price; }
このうちのsuper();
というコードは、親クラス(Super class)のコンストラクターを呼び出していますが、このコードは無くても良いので削除します。
また、引数のnameがnullだったりpriceが0以下だったり不正な値の場合はエラーになるようにassert
文を追加します。
public Snack(String name, int price) { assert name != null; assert price > 0; this.name = name; this.price = price; }
この修正を保存するとDemo
クラスに赤い×アイコンが付いたと思います。
デフォルトコンストラクター
3カ所に赤い×アイコンが付いていると思いますが、これはデフォルトコンストラクターが見つからないためのエラーです。 画面下の"問題"ビューを見ると(Fig14)、"コンストラクタ― Snack() は未定義です" というエラーが3つ表示されていると思います。
クラスに明示的にコンストラクタ―を1つも実装しない場合、デフォルトコンストラクタ―という暗黙のコンストラクターが追加されます。(ソースコード上はみえません) デフォルトコンストラクタ―は引数を取らず、また何の処理もしないコンストラクターです。
public Snack() { super(); }
これまでオブジェクトの生成は以下のようにコーディングしていましたが、このときに使用されるコンストラクターはデフォルトコンストラクターです。
Snack umaibouSalami = new Snack();
上記で2つの引数を取るコンストラクタ―を明示的に実装したことによりデフォルトコンストラクタ―が追加されなくなったため、デフォルトコンストラクターが見つからず(未定義)エラーになった、ということです。
Snack umaibouSalami = new Snack(); // この行がエラー umaibouSalami.setName("うまいぼう サラミ味"); umaibouSalami.setPrice(10); umaibouSalami.setIngredients("コーン,植物油脂,糖類,ポークパウダー,香辛料,パン粉,ビーフパウダー,酵母エキスパウダー,パセリ,調味料,香料,甘味料,カラメル色素,酸化防止剤");
このエラーを解消するために実装したコンストラクターを使うように修正します。同時にセッターメソッドで値をセットしているコードも不要になるので削除します。
Snack umaibouSalami = new Snack("うまいぼう サラミ味", 10); //umaibouSalami.setName("うまいぼう サラミ味"); // 不要になった行なので削除 //umaibouSalami.setPrice(10); // 不要になった行なので削除 umaibouSalami.setIngredients("コーン,植物油脂,糖類,ポークパウダー,香辛料,パン粉,ビーフパウダー,酵母エキスパウダー,パセリ,調味料,香料,甘味料,カラメル色素,酸化防止剤");
原材料のingredients
フィールドはオプション的な扱いなので、セットすべき値がある場合は明示的にセッターで値をセットします。
もし、原材料が不明な場合はingredients
フィールドに"未定”とセットしたい、という仕様があった場合はセッターで以下のようにコーディングするのではなく
umaibouSalami.setIngredients("未定");
以下のようにコンストラクターでセットする方が適切です。
public Snack(String name, int price) { assert name != null; assert price > 0; this.name = name; this.price = price; this.ingredients = "未定"; // オブジェクト生成直後は未定という値を持つ }
複数のコンストラクターを実装する
1つのクラスにコンストラクターを複数実装することができるので、Snack
クラスに3つの引数を取るコンストラクタ―を追加してみます。これをコンストラクタ―のオーバーロードといいます。
以下がこれまで実装したコンストラクタ―のコードです。
public Snack(String name, int price) { assert name != null; assert price > 0; this.name = name; this.price = price; this.ingredients = "未定"; } public Snack(String name, int price, String ingredients) { assert name != null; assert price > 0; this.name = name; this.price = price; this.ingredients = ingredients; }
これで、原材料にセットする値があるおかしの場合もコンストラクタ―でオブジェクトを初期化できます。
Snack umaibouSalami = new Snack("うまいぼう サラミ味", 10, "コーン,植物油脂,糖類,ポークパウダー,香辛料,パン粉,ビーフパウダー,酵母エキスパウダー,パセリ,調味料,香料,甘味料,カラメル色素,酸化防止剤");
コンストラクタ―から他のコンストラクタ―を呼ぶ
このコンストラクタ―の実装では、this.name
とthis.price
をセットするコードがまったく同じことを行っています。なのでこの重複するコードを以下のように最適化します。
まず、2つの引数を取るコンストラクタ―をthis(name, price, "未定");
というように修正しました。このコードのthis( ... )
という部分が3つの引数を取るコンストラクタ―を呼び出しています。これで重複するコードが取り除けました。
public Snack(String name, int price) { this(name, price, "未定"); // 3つの引数を取るコンストラクターを呼ぶ } public Snack(String name, int price, String ingredients) { assert name != null; assert price > 0; this.name = name; this.price = price; this.ingredients = ingredients; }
このコンストラクターでは"未定"という文字列が2カ所に表れているので、これを定数にします。
また、this.ingredients
は引数でnullが渡された場合は"未定"という文字列をセットするように3項演算子を使うように修正します。
private static final String UNDEFINED_INGREDIENTS = "未定"; public Snack(String name, int price) { this(name, price, UNDEFINED_INGREDIENTS); } public Snack(String name, int price, String ingredients) { assert name != null; assert price > 0; this.name = name; this.price = price; this.ingredients = ingredients == null ? UNDEFINED_INGREDIENTS : ingredients; }
レッスン1のさいごに
レッスン1は以上です。レッスン1ではクラス、フィールド、コンストラクタ―をEclipseの機能を使って書く方法を説明してきました。 Eclipseの機能を使うことでコーディングがより楽になります。
これまでに書いたJavaのソースコードは以下のようになります。
Snack.java
package com.example.lesson01.model; public class Snack { private static final String UNDEFINED_INGREDIENTS = "未定"; public Snack(String name, int price) { this(name, price, UNDEFINED_INGREDIENTS); } public Snack(String name, int price, String ingredients) { assert name != null; assert price > 0; this.name = name; this.price = price; this.ingredients = ingredients == null ? UNDEFINED_INGREDIENTS : ingredients; } /** * 名前 (必須) */ private String name; /** * 値段 (必須) */ private int price; /** * 原材料 (任意) */ private String ingredients; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public String getIngredients() { return ingredients; } public void setIngredients(String ingredients) { this.ingredients = ingredients; } @Override public String toString() { return "Snack [name=" + name + ", price=" + price + ", ingredients=" + ingredients + "]"; } }
Demo.java
package com.example.lesson01; import com.example.lesson01.model.Snack; public class Demo { public static void main(String[] args) { System.out.println("Lession01 Demo start"); // サラミ味のおかしを生成 Snack umaibouSalami = new Snack("うまいぼう サラミ味", 10, "コーン,植物油脂,糖類,ポークパウダー,香辛料,パン粉,ビーフパウダー,酵母エキスパウダー,パセリ,調味料,香料,甘味料,カラメル色素,酸化防止剤"); // チーズ味のおかしを生成 Snack umaibouCheese = new Snack("うまいぼう チーズ味", 10, "コーン,植物油脂,チーズパウダー,乳糖,クリーミングパウダー,乳製品,パン粉,砂糖,食塩,香辛料,調味料,香料,パプリカ色素,甘味料,ph調整剤,乳化剤,ターメリック色素"); // めんたい味のおかしを生成 Snack umaibouMentai = new Snack("うまいぼう めんたい味", 10, "コーン,植物油脂,糖類,パプリカ,香辛料,パン粉,たん白加水分解物,たら調味パウダー,食塩,調味料,香料,パプリカ色素,甘味料"); System.out.println(umaibouSalami.toString()); System.out.println(umaibouCheese.toString()); System.out.println(umaibouMentai.toString()); System.out.println("Lession01 Demo end"); } }
続く後編ではJavaコードの書き方をもう少し踏み込んで説明します。(現在記事作成中です)
rubytomato.hateblo.jp