12 命令をつくる(1):メソッド・引数付メソッド

12.1 学習目標

12.2 メソッド

12.2.1 メソッドとその目的

メソッドは、複数の命令のまとまりに名前をつけて、一つの命令として扱うことが出来る仕組みです。

メソッドを作ることで、

というメリットがあります。

12.2.2 メソッド定義とメソッド呼び出し

以下のプログラムは、メソッドを使って四角形を描くプログラムです。

リスト 12.2.2.1 DrawRectangleMethod.java
  1: /*
  2:  * 例題1:四角形を描くプログラム
  3:  * (メソッドの作り方の練習)
  4:  * 作成者:MegumiAraki
  5:  * 作成日:2007/06/09
  6:  * メールアドレス:garnet@sfc.keio.ac.jp
  7:  */
  8: public class DrawRectangleMethod extends Turtle {
  9: 
 10: 	// 起動処理
 11: 	public static void main(String[] args) {
 12: 		Turtle.startTurtle(new DrawRectangleMethod());
 13: 	}
 14: 
 15: 	// タートルを動かす処理
 16: 	public void start() {
 17: 		drawRectangle();
 18: 	}
 19: 
 20: 	// 四角形を描く
 21: 	void drawRectangle() {
 22: 		for (int i = 0; i < 4; i++) {
 23: 			fd(50);
 24: 			rt(90);
 25: 		}
 26: 	}
 27: }

ここ をクリックすると、プログラムをダウンロードできます。

下のボタンを押すと、DrawRectangleMethodプログラムが実行できます。

メソッドを使うためには、メソッドを定義し、そのメソッドを呼び出す必要があります。

メソッドは一度定義すれば、同じメソッドを何度も呼び出して使うことができます。

このプログラムでは21行目でメソッドを定義し、17行目で呼び出しています。

					
21: void drawRectangle(){
22: 	for (int i = 0; i < 4;i++) {
23: 		fd(50);
24: 		rt(90);
25: 	}
26: }

				
17: drawRectangle();
				

引数・戻り値なしのメソッド定義、メソッド呼び出しの一般形は以下の通りです

void [メソッド名](){

}

				
[メソッド名]();
while文とfor文

このプログラムでは、繰り返しをfor文を使って書いています。for文を使うと、while文よりも短く書くことができます。

for文の()の中の命令は、それぞれwhile文と以下のように対応しています。

図 124 while文とfor文

i = i + 1 と i++ は、いずれも i に 1 を足す、という意味です。while文で i++ と書くことも、for文で i = i + 1 と書くこともできます。

12.2.3 メソッドの処理の順序

以下のプログラムは、四角形を描くメソッドを使って、四角形を3つ描くプログラムです。

リスト 12.2.3.1 DrawThreeRectanglesMethod.java
  1: /*
  2:  * 例題2:四角形を3つ描くプログラム
  3:  * (メソッド処理の順序)
  4:  * 作成者:MegumiAraki
  5:  * 作成日:2007/06/09
  6:  * メールアドレス:garnet@sfc.keio.ac.jp
  7:  */
  8: 
  9: public class DrawThreeRectanglesMethod extends Turtle {
 10: 
 11: 	// 起動処理
 12: 	public static void main(String[] args) {
 13: 		Turtle.startTurtle(new DrawThreeRectanglesMethod());
 14: 	}
 15: 
 16: 	// タートルを動かす処理
 17: 	public void start() {
 18: 		// 四角形を3つ描く
 19: 		for (int i = 0; i < 3; i++) {
 20: 			drawRectangle();// 四角形を描く
 21: 			move();// 次の描く位置まで移動する
 22: 		}
 23: 	}
 24: 
 25: 	// 四角形を描く
 26: 	void drawRectangle() {
 27: 		for (int i = 0; i < 4; i++) {
 28: 			fd(50);
 29: 			rt(90);
 30: 		}
 31: 	}
 32: 
 33: 	// 次の描く位置まで移動する
 34: 	void move() {
 35: 		up();
 36: 		rt(90);
 37: 		fd(60);
 38: 		lt(90);
 39: 		down();
 40: 	}
 41: }

ここ をクリックすると、プログラムをダウンロードできます。

下のボタンを押すと、DrawThreeRectanglesMethodプログラムが実行できます。

メソッドが呼び出されると、プログラムの処理はそのメソッドの処理に飛びます。 そして、メソッドが終了すると、メソッド呼び出し位置に返ってきます。

図 12.2.3.1 メソッドの処理の順序

四角形を3つ描くプログラムでは、まず、四角形を描くメソッドを呼び、 四角形を描き終わったら、次の描く位置まで移動するメソッドを呼び、 移動し終わったら、再び四角形を描くメソッドを呼び…という処理を3回繰り返しています。

12.2.4 メソッドの定義位置の注意点

次のプログラムは、四角形を描くプログラムを書こうとして、失敗した例です。

リスト 12.2.4.1 DrawRectangleMethodError.java
  1: /*
  2: * 四角形を描くプログラム(コンパイルエラー)
  3: * (メソッド定義の間違い)
  4: * 作成者:MegumiAraki
  5: * 作成日:2007/06/09
  6: * メールアドレス:garnet@sfc.keio.ac.jp
  7: */
  8: 
  9: public class DrawRectangleMethodError extends Turtle {
 10: 	
 11: 	//起動処理
 12: 	public static void main(String[] args) {
 13: 		Turtle.startTurtle(new DrawRectangleMethodError());
 14: 	}
 15: 	
 16: 	//タートルを動かす処理
 17: 	public void start() {
 18: 		
 19: 		drawRectangle();// 四角形を描く処理を呼び出す
 20: 
 21: 		//四角形を描く
 22: 		void drawRectangle(){
 23: 			for (int i = 0; i < 4; i++) {
 24: 				fd(50);
 25: 				rt(90);
 26: 			}
 27: 		}
 28: 
 29: 	}
 30: }

このプログラムを実行しようとすると、以下のようなエラーが出ます。

DrawRectangleMethodError.java:22: 式の開始が不正です。
		void drawRectangle(){
		^
DrawRectangleMethodError.java:22: ';' がありません。
		void drawRectangle(){
		                  ^
エラー 2 個

					

これは、メソッドの中にメソッドを定義しているためです。 このプログラムでは、startメソッドの中に、drawRectangleメソッドを定義しています。

図 12.2.4.1 メソッド定義のミス

Javaでは、メソッドの中にメソッドを定義することはできません。( 2章「プログラムの要素」参照 ) メソッドは、クラスブロックの中に書く必要があります。 正しいメソッド定義は以下のとおりです。

図 12.2.4.2 正しいメソッド定義

12.3 引数付メソッド

12.3.1 引数とその目的

メソッドブロック内で宣言された変数は、メソッドブロック内でしか有効ではありません。 しかし、あるメソッドから他のメソッドを呼ぶときに、データを受け渡したいことがあります。 引数とは、メソッドブロック外と、メソッドブロック内でデータをやり取りする仕組みです。 引数を使うことで、メソッドブロック外から、メソッドブロック内にデータを受け取ることができます。

12.3.2 引数を用いた、四角形を描くメソッドの抽象化

引数が使えない場合、次のように大きさが違う四角形を書きたい場合も、 2つのメソッドを作る必要があります。

図 12.3.2.1 メソッドの設計
リスト 12.3.2.1 DrawTwoRectangles1.java
  1: /*
  2:  * 四角を二つ描くプログラム(引数がないメソッドを使ったもの)
  3:  * 作成者:Yoshiaki Matsuzawa
  4:  * 作成日:2011/12/06
  5:  */
  6: public class DrawTwoRectangles1 extends Turtle {
  7: 
  8: 	// 起動処理
  9: 	public static void main(String[] args) {
 10: 		Turtle.startTurtle(new DrawTwoRectangles1());
 11: 	}
 12: 
 13: 	// タートルを動かす処理
 14: 	public void start() {
 15: 		drawBigRectangle();
 16: 		drawSmallRectangle();
 17: 	}
 18: 
 19: 	// 一辺100の大きな四角形を書く
 20: 	void drawBigRectangle() {
 21: 		for (int i = 0; i < 4; i++) {
 22: 			fd(100);
 23: 			rt(90);
 24: 		}
 25: 	}
 26: 
 27: 	// 一辺20の小さな四角形を書く
 28: 	void drawSmallRectangle() {
 29: 		for (int i = 0; i < 4; i++) {
 30: 			fd(20);
 31: 			rt(90);
 32: 		}
 33: 	}
 34: }

ここ をクリックすると、プログラムをダウンロードできます。

下のボタンを押すと、DrawTwoRectangles1プログラムが実行できます。

次のプログラムでは、引数を使って大きさを指定し、大きい四角形と小さな四角形を「四角形を描く」という ひとつのメソッドで描けるようにしています。

図 12.3.2.2 メソッドの設計
リスト 12.3.2.2 DrawTwoRectangles2.java
  1: /*
  2:  * 四角を二つ描くプログラム(大きさを引数としたもの)
  3:  * 作成者:Yoshiaki Matsuzawa
  4:  * 作成日:2011/12/06
  5:  */
  6: public class DrawTwoRectangles2 extends Turtle {
  7: 
  8: 	// 起動処理
  9: 	public static void main(String[] args) {
 10: 		Turtle.startTurtle(new DrawTwoRectangles2());
 11: 	}
 12: 
 13: 	// タートルを動かす処理
 14: 	public void start() {
 15: 		drawRectangle(100);
 16: 		drawRectangle(20);
 17: 	}
 18: 
 19: 	// 一辺がsizeの四角形を書く
 20: 	void drawRectangle(int size) {
 21: 		for (int i = 0; i < 4; i++) {
 22: 			fd(size);
 23: 			rt(90);
 24: 		}
 25: 	}
 26: 
 27: }

ここ をクリックすると、プログラムをダウンロードできます。

下のボタンを押すと、DrawTwoRectangles2プログラムが実行できます。

引数付メソッドを使うためには、引数付メソッドを定義し、そのメソッドを引数付で呼び出します。 一般形は以下の通りです。

					
void [メソッド名]([引数の型] [仮引数名]){

}

				
[メソッド名]([実引数]);

呼び出し部分の引数を実引数、宣言部分の引数を仮引数と呼びます。実引数(メソッドブロック外にあるデータ)が、 仮引数(メソッドブロック内で使える変数)に代入され、メソッドブロック内でその変数の値が使えるようになります。

12.3.3 引数を用いた、多角形を描くメソッドの抽象化

家を書くプログラムでは,三角形と四角形を書くために、 2つのメソッドを作る必要があります。

図 12.3.3.1 メソッドの設計
リスト 12.3.3.1 NewHouse1.java
  1: /*
  2:  * 家を描くプログラム(四角形と三角形を書くもの)
  3:  * 作成者:Yoshiaki Matsuzawa
  4:  * 作成日:2011/12/06
  5:  */
  6: public class NewHouse1 extends Turtle {
  7: 
  8: 	// 起動処理
  9: 	public static void main(String[] args) {
 10: 		Turtle.startTurtle(new NewHouse1());
 11: 	}
 12: 
 13: 	// タートルを動かす処理
 14: 	public void start() {
 15: 		drawTriangle(100);
 16: 		rt(90);
 17: 		drawRectangle(100);
 18: 	}
 19: 
 20: 	// 三角形を書く
 21: 	void drawTriangle(int size) {
 22: 		rt(30);
 23: 		for (int i = 0; i < 3; i++) {
 24: 			fd(size);
 25: 			rt(120);
 26: 		}
 27: 		lt(30);
 28: 	}
 29: 
 30: 	// 四角形を書く
 31: 	void drawRectangle(int size) {
 32: 		for (int i = 0; i < 4; i++) {
 33: 			fd(size);
 34: 			rt(90);
 35: 		}
 36: 	}
 37: 
 38: }

ここ をクリックすると、プログラムをダウンロードできます。

下のボタンを押すと、NewHouse1プログラムが実行できます。

次のプログラムでは「屋根を描く」処理で使っていた三角形と、「壁を描く」処理で使っていた四角形を 「多角形を描く」というひとつのメソッドで描けるようにしています。

図 12.3.3.2 メソッドの設計
リスト 12.3.3.2 NewHouse2.java
  1: /*
  2:  * 家を描くプログラム(四角形と三角形を書くもの)
  3:  * 作成者:Yoshiaki Matsuzawa
  4:  * 作成日:2011/12/06
  5:  */
  6: public class NewHouse2 extends Turtle {
  7: 
  8: 	// 起動処理
  9: 	public static void main(String[] args) {
 10: 		Turtle.startTurtle(new NewHouse2());
 11: 	}
 12: 
 13: 	// タートルを動かす処理
 14: 	public void start() {
 15: 		drawRegularPolygon(3, 100);
 16: 		rt(90);
 17: 		drawRegularPolygon(4, 100);
 18: 	}
 19: 
 20: 	// 指定された角数の正多角形を描く
 21: 	void drawRegularPolygon(int n, int size) {
 22: 		// 向きを調節する
 23: 		double angle = 360d / (double) n;
 24: 		rt(angle - 90);
 25: 
 26: 		// 多角形を描く
 27: 		for (int i = 0; i < n; i++) {
 28: 			fd(size);
 29: 			rt(angle);
 30: 		}
 31: 
 32: 		// 向きを上向きに戻す
 33: 		lt(angle - 90);
 34: 	}
 35: 
 36: }

ここ をクリックすると、プログラムをダウンロードできます。

下のボタンを押すと、NewHouse2プログラムが実行できます。

12.4 変数の有効範囲と引数

12.4.1 変数の有効範囲

次のプログラムは、一辺の長さを指定して四角形を描くプログラムを書こうとして、失敗した例です。

リスト 12.4.1.1 DrawVariableRectangleMethodError.java
  1: /*
  2:  * 四角形を描くプログラム(コンパイルエラー)
  3:  * (引数ありメソッドの練習)
  4:  * 作成者:MegumiAraki
  5:  * 作成日:2007/06/09
  6:  * メールアドレス:garnet@sfc.keio.ac.jp
  7:  */
  8: 
  9: public class DrawVariableRectangleMethodError extends Turtle {
 10: 
 11: 	//起動処理
 12: 	public static void main(String[] args) {
 13: 		Turtle.startTurtle(new DrawVariableRectangleMethodError());
 14: 	}
 15: 	
 16: 	//タートルを動かす処理
 17: 	void start() {
 18: 
 19: 		// 一辺の長さの入力を受け取る
 20: 		int length = 0;
 21: 		print("一辺の長さを入力してください");
 22: 		length = input();
 23: 		
 24: 		drawRectangle();// 一辺の長さを指定して四角形を描く
 25: 
 26: 	}
 27: 
 28: 	//四角形を描く
 29: 	void drawRectangle(){
 30: 		for (int i = 0; i < 4; i++) {
 31: 			fd(length);
 32: 			rt(90);
 33: 		}
 34: 	}
 35: }

大きさを変えて四角形を描くプログラム(コンパイルエラー)を実行しようとすると、以下のようなエラーが出ます

					
DrawRectangleMethodError.java:31: シンボルを見つけられません。
シンボル: 変数 length
場所 : DrawRectangleMethodError の クラス
					fd(length);

				

fd(length)のlengthという変数が見つけられないということを意味しています。

これは、drawRectangle()メソッドの内部({と}で囲われた部分)が、lengthという変数の有効範囲外であるためです。

図 12.4.1.1 変数の有効範囲

12.4.2 引数付メソッド定義とメソッド呼び出し

以下のプログラムは、引数を使って、メソッドの有効範囲外から四角形の長さを渡せるようにしたプログラムです。

入力された長さのlength(実引数)を、メソッドにlength(仮引数)として渡し、四角形を描いています。

リスト 12.4.2.1 DrawVariableRectangleMethod.java
  1: /*
  2:  * 四角形を描くプログラム
  3:  * (引数ありメソッドの練習)
  4:  * 作成者:MegumiAraki
  5:  * 作成日:2007/06/09
  6:  * メールアドレス:garnet@sfc.keio.ac.jp
  7:  */
  8: public class DrawVariableRectangleMethod extends Turtle {
  9: 
 10: 	// 起動処理
 11: 	public static void main(String[] args) {
 12: 		Turtle.startTurtle(new DrawVariableRectangleMethod());
 13: 	}
 14: 
 15: 	// タートルを動かす処理
 16: 	public void start() {
 17: 		// 一辺の長さの入力を受け取る
 18: 		int inputLength = 0;
 19: 		print("一辺の長さを入力してください");
 20: 		inputLength = input();
 21: 
 22: 		drawRectangle(inputLength);// 入力された長さを一辺の長さとして四角形を描く
 23: 	}
 24: 
 25: 	// 四角形を描く
 26: 	void drawRectangle(int length) {
 27: 		for (int i = 0; i < 4; i++) {
 28: 			fd(length);
 29: 			rt(90);
 30: 		}
 31: 	}
 32: }

ここ をクリックすると、プログラムをダウンロードできます。

下のボタンを押すと、DrawVariableRectangleMethodプログラムが実行できます。

					
29: void drawRectangle(int length){
30: 	for (int i =0; i < 4; i++) {
31: 		fd(length);
32: 		rt(90);
33: 	}
34: }

				
24: drawRectangle(inputLength);//入力された長さを一辺の長さとして四角形を描く

				

12.5 メソッドの設計・あるいはプログラムの構造化

メソッドからメソッドを呼ぶことが出来るため、メソッドの連鎖を用いてプログラムを作ることができます。 これは「構造化プログラミング」という、複雑さを制御するための基本的設計技法です。

複雑になると、メソッドの呼び出し関係が混乱してくるので、まず以下のようなメソッド構成図を書き、 プログラムを書いていくと良いでしょう。

図 12.5.1 メソッドの設計

この設計を実装したものを下に載せます.

12.5.1 窓付きの家を描くプログラム(引数を用いた、多角形を描くメソッドの抽象化)

リスト 12.5.1.1 House05.java
  1: /*
  2:  * 窓付きの家を描くプログラム(引数による多角形を描くメソッドの抽象化)
  3:  * 作成者:MegumiAraki
  4:  * 作成日:2007/06/09
  5:  * メールアドレス:garnet@sfc.keio.ac.jp
  6:  */
  7: 
  8: public class House05 extends Turtle {
  9: 
 10: 	//起動処理
 11: 	public static void main(String[] args) {
 12: 		Turtle.startTurtle(new House05());
 13: 	}
 14: 
 15: 	// 家を描く
 16: 	 //タートルを動かす処理
 17: 	public void start() {
 18: 		drawRoof(); // 屋根を描く
 19: 		drawWall(); // 壁を描く
 20: 		drawWindow(); // 窓を描く
 21: 	}
 22: 
 23: 	// 屋根を描く
 24: 	void drawRoof() {
 25: 		drawRegularPolygon(3, 80); // 三角形を描く
 26: 	}
 27: 
 28: 	// 壁を描く
 29: 	void drawWall() {
 30: 		rt(90); // 向きを調節する
 31: 		drawRegularPolygon(4, 80);// 四角形を描く
 32: 		lt(90);// 向きを上向きに戻す
 33: 	}
 34: 
 35: 	// 窓を描く
 36: 	void drawWindow() {
 37: 		// 窓を描く位置まで移動する
 38: 		moveToWindowLocation(22);
 39: 
 40: 		// 窓を描く
 41: 		rt(90);
 42: 		for (int i = 0; i < 4; i++) {
 43: 			drawRegularPolygon(4, 16);
 44: 			fd(16 * 2 + 4);
 45: 			rt(90);
 46: 		}
 47: 		lt(90);
 48: 	}
 49: 
 50: 	// 指定された角数の正多角形を描く
 51: 	void drawRegularPolygon(int n, int size) {
 52: 		// 向きを調節する
 53: 		double angle = 360d / (double) n;
 54: 		rt(angle - 90);
 55: 
 56: 		// 多角形を描く
 57: 		for (int i = 0; i < n; i++) {
 58: 			fd(size);
 59: 			rt(angle);
 60: 		}
 61: 
 62: 		// 向きを上向きに戻す
 63: 		lt(angle - 90);
 64: 	}
 65: 
 66: 	// 窓を描く位置まで移動する
 67: 	void moveToWindowLocation(int length) {
 68: 		moveTurtle(90, 22);// 右へ
 69: 		moveTurtle(180, 22);// 下へ
 70: 	}
 71: 
 72: 	// 指定された方向に(ペンを上げて)移動する
 73: 	void moveTurtle(double direction, int distance) {
 74: 		up();
 75: 		rt(direction);
 76: 		fd(distance);
 77: 		lt(direction);
 78: 		down();
 79: 	}
 80: 
 81: }

ここ をクリックすると、プログラムをダウンロードできます。

下のボタンを押すと、House05プログラムが実行できます。

ライブラリ

実は今まで使っていたfd,rtという命令は,以下のようなメソッドとして定義されていたのでした。

ある目的のために使うメソッドの集まりを作り、メソッド群を再利用します。 このメソッドの集まりのことを「ライブラリ」といいます。 fd, rtなどのタートルに使う命令は「タートルライブラリ」としてどこかに定義されているのです。

12.6 練習問題

12.6.1 円を描くメソッドを作ろう

円を描くメソッド「void drawCircle()」を作ってください。 できたら、startメソッドから2回以上呼び出して、うまく動作するか確かめてみよう。

ファイル名は「Circle2.java」とすること.

12.6.2 大きさが変わる家を描くメソッドを作ろう

大きさを指定して家を描くメソッド(窓はなくて良い)「void drawHouse(int size)」を作ってください。 できたら、startメソッドから2回以上呼び出して、うまく動作するか確かめてみよう。

ファイル名は「TwoHouses.java」とすること.

12.6.3 中心角を指定して円弧を描くメソッドを作ろう

中心角を指定して円弧を描くメソッド「void drawArc(int angle)」を作ってください。

(ヒント:中心角が360ならば円に、180ならば半円に、1ならば点のようになります。以下に、120度の場合と、300度の場合の例を示します)

図 12.6.3.1 円弧を描くメソッド
図 12.6.3.2 円弧を描くメソッド2

12.6.4 レモン型の図形を描くメソッドを作ろう

drawArc(int angle)を利用してレモン型の図形を描くメソッド「void drawLemon()」を作ってください。

図 12.6.4.1 レモン型の図形を描くメソッド

12.6.5 メソッドの多段呼び出しの練習をしよう

蝶を描くメソッドdrawButterfly()を作ってください。 メソッド構造図による設計もすること。 (ヒント:円弧を描くメソッドのほかにも、レモン型を描くメソッドなどを部品として使う)

図 12.6.5.1 蝶を描くメソッド

ファイル名は「Butterfly.java」とすること.

12.6.6 メソッドの再利用をしよう

drawLemon()を再利用して、drawFlower()のように花を描くメソッドを作ろう。

図 12.6.6.1 花を描くメソッド

ファイル名は「Flower.java」とすること.

12.6.7 マス目

x行y列のマス目を書くメソッドを作ろう。以下のような定義を持つ

					
void drawMasume(int row, int col, int size) {...なかみ...}

				

出力例を以下に示す.

					
drawMasume(2, 3, 50);					

				
図 12.6.7.1 23
					
drawMasume(5, 7, 20);					

				
図 12.6.7.2 57

ファイル名は「Masume.java」とすること.

12.6.8 構造化プログラミングによる自由作品

「1メソッド10行以内!」というルールで,図形を書くプログラムを作ろう.

ファイル名は「Structured.java」とすること.