メソッドの定義と呼び出し
10.2 メソッドの定義と呼び出し
Javaでは様々なメソッドが既に用意されていますが、メソッドは自分でも作成することができます。メソッドを作成しながら、メソッドの構成を理解していきましょう。
これは、引数に受け取った2つの整数を加算し結果を返すメソッドです。
① ソース・フォルダー :myproj_intro/src
② パッケージ :jp.co.f1.intro.ch10
③ 名前 :MyAdditionMethod
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる
➢ MyAdditionMethod.java
package jp.co.f1.intro.ch10; public class MyAdditionMethod { static int additionMethod(int a, int b){ int sum = a + b; return sum; } public static void main(String[] args) { //計算用の値を管理する変数の宣言と初期化 int a = 5; int b = 10; int answer = additionMethod(a, b); System.out.println("a = " + a); System.out.println("b = " + b); System.out.println("a + b = " + answer); } }
実行結果
このプログラムの流れ
このプログラムでは、5~11行目でメソッドを作成しています。このメソッドは、指定された変数aと指定された変数bを足して、その計算結果を返すものです。5行目のadditionメソッド前に「static」修飾子がついている理由は、19行目でadditionMethodメソッドを呼び出す側がstaticの付いているstatic void mainメソッド内に記述されているからです。
16、17行目では、5~11行目で作成したメソッドを呼び出す時に使う変数を宣言し、初期化しています。
5~11行目に作成したメソッドは、19行目の右辺addtionMethod(a,b)で呼び出して実行しています。また、呼び出す際には5~11行目のメソッドの処理を行う際に必要な情報であるint型の引数2つに変数aと変数bを設定しています。
5~11行目のメソッドでは、変数aの値である5と変数bの値である10を加算し、その答えをint型で返す処理を行っています。メソッドを実行して返ってきた結果の値は15なので、int型の変数answerに15が代入されます。
変数a、変数b、変数answerを表示します。
このプログラムを例にして、次の項からメソッドの詳しい説明をしていきます。
10.2.2 基本構文
メソッドの基本構文は、以下のようになります。
このように、メソッドは処理を記述し定義部分を呼び出すことで、実際に処理をさせることができます。
また、ここに示した書式はあくまで一例です。記述の仕方など、詳しくは次の項から説明します。
10.2.3 メソッドの定義
メソッドの定義の書式を詳しく説明します。
①static修飾子
static修飾子は、これから定義するメソッドを、どのような範囲・形態で利用できるか、ということを表します。これは、Javaのオブジェクト指向プログラミングに関わることなので、ここでの詳しい説明は省略し、「Java基礎」のテキストで詳しく説明します。
②戻り値の型 ⑥return文と戻り値
戻り値は、そのメソッドで処理をして得られる結果のことで、メソッドの呼び出し元の処理で利用されます。戻り値を持つメソッドの場合は、必ずreturn文であらかじめ宣言していた型(intやdoubleなど)の戻り値を返さなくてはなりません。1つの値、もしくは1つの変数のみを返すことができます。
戻り値を持たないメソッドの場合、voidと記述します。voidは、戻り値を持たない、返さない、という意味です。
ポイント
・ メソッドに指定する戻り値の型と、return文で返す戻り値の型は一致しなければならない。
・ 戻り値がないメソッドの場合はvoidと記述する。
③メソッド名
メソッド名は、メソッドにつけた名前です。メソッド名は小文字から始まり、2つ以上の単語を繋げた名前にしている場合は2つ目以降の単語の頭文字を大文字にする(camel case)のが慣例となっています。
④引数
引数は、メソッドを呼び出す時にそのメソッドに渡す値です。メソッドが受け取った引数は、メソッド内の処理で利用されます。
メソッドの定義部分に記述する引数を仮引数と呼びます。メソッド名の後ろの括弧の中には、必要な引数の型と変数名を記述しなくてはなりません。引数を複数受け取るメソッドの場合は、カンマで区切ります。図 10.2.1は、int型の引数2つを受け取るメソッドの一例です。また、引数を受け取らない場合は括弧の中には記述しません。この場合は図 10.2.2のようになります
図 10.2.1 : int型の引数2つを受け取るメソッドの一部
図 10.2.2 : 引数を受け取らないメソッドの一部
仮引数は、メソッド内の処理で利用されます。メソッドの宣言部分は「{ }」で囲みます。これは、for文などの繰り返し文やif文などの条件文と同じくブロックと言います。仮引数はブロック内でのみ有効で、ブロック外で利用することはできません。
メソッドを呼び出す際に記述する引数を実引数と呼びます。実引数は、メソッドの宣言部分に書かれた引数の型、記述した順番、個数に一致させる必要があります。変数名は同じでなくともかまいませんが、一致させるか似た名前になるようにするとわかりやすいでしょう。また、変数ではなく値をそのまま入れることもできます。引数が複数ある場合は、カンマで区切ります。
図 10.2.3と図 10.2.4は、int型の引数とdouble型の引数を受け取るメソッドを呼び出す場合の実引数の記述方法を示したもので、どちらも同じ処理になります。型と順番が一致していることに注意して下さい。
図 10.2.3 : int型の引数とdouble型の引数を受け取るメソッドを呼び出す場合
図 10.2.4 : 実引数に値を記述した場合
図 10.2.5 : 引数を受け取らないメソッドを呼び出す場合
また、自分でメソッドを作成する場合には、そのメソッドの機能によって引数が必要か不要かを決定します。メソッドを呼び出す時に、メソッド内の処理で利用したい値がある場合は、引数によってその値をメソッド内に渡します。
ポイント
・ 仮引数と実引数は、引数の型、並び順、個数を一致させる。
・ 引数が複数ある場合は「,(カンマ)」で区切る。引数がない場合は、「 ( ) 」の中に何も書かない。
⑤処理
メソッドの処理内容を書きます。引数を設定したメソッドの場合は、それを利用して処理を行います。
引数と戻り値とメソッドの組み合わせパターン
引数と戻り値の有無によりメソッドの組み合わせは若干変化します。
大きく分けて次の④パターンになります。
・ 引数あり、戻り値あり
・ 引数あり、戻り値なし
・ 引数無し、戻り値あり
・ 引数無し、戻り値なし
10.2.4 メソッドの呼び出しと処理の流れ
ここでは、メソッドを呼び出した場合にどのような流れで処理が実行されるのかを解説します。
メソッド本体と呼び出し側の関係は図 10.2.6のようになります。一見複雑な動きに見えますが、一つずつ見ていくと、それほど難しいものではないことがわかります。図を見ながら処理の流れをを追ってみて下さい。
※ 変数aの値は5、変数bの値は10とする。
① 2つ引数の値をメソッド定義(本体)に渡す。
② 渡された値を使った処理を行う。ここでは、変数aと変数bの加算を行い、変数sumに代入する。
③ 戻り値に変数sumの値を設定する。
④ 呼び出し元にretrun文の結果(ここでは、15)が戻り値として返ってくる。
⑤ 変数answerにメソッドの戻り値である15を代入する。
図 10.2.6 : メソッドの呼び出しとメソッド定義部分の動作
次の図 10.2.7では、この①~⑤の手順ごとに詳しく説明します。
図 10.2.7 : メソッドの呼び出しとメソッド本体の動作のイメージ
メソッド名を記述してメソッドを呼び出すと、その時点で実引数で指定した値がメソッド本体の同じ並びの仮引数に渡されます。メソッドは渡された引数を基に処理を行い、処理結果を戻り値として呼び出した側に返します。
※メソッドの定義によって、引数がないメソッドや戻り値のないメソッドもあるので注意が必要です。
以上がメソッドの基本的な形になります。
10.2.5 メソッドを定義する位置
メソッドを定義する場所は、mainメソッドの前後どちらでもかまいませんが、何らかのクラスの中に入っている必要があり、また、メソッドは入れ子になってはなりません。
次の2つのソースコードで示しているように、mainメソッドの上でも下でも、どちらでも問題はありません。
10.2.6 メソッドを部品として扱う
メソッドを使う最大のメリットは、メソッドを部品のように扱えることです。このメリットを、プログラムを作成しながら理解していきましょう。
これから作成していく「NoMethod.java」と「Method.java」という2つのプログラムは、どちらも4名の生徒のテストの点数を管理し、名前と点数と共に合否を表示するものですが、片方はメソッドを使用せず、もう片方はメソッドを使用します。4名の点数をプログラムに登録し、「名前の表示、合格の時の表示、不合格の時の表示、境界線(- – -)の表示」という処理を4名分順に行います。
➢ NoMethod.java
メソッドを作成せず、全ての処理をmainメソッドに記述したプログラムです。
➢ Method.java
部品として使うメソッドを作成し、それを呼び出して使います。
メソッドを作成せずに記述したNoMethod.javaとメソッドを作成し利用したMethod.javaとの構造の違いを図に表したものが図 10.2.8です。
図 10.2.8 : メソッドの利用の有無でのプログラム構造の違い
「合格の時の表示、不合格の時の表示、境界線の表示」という処理は、4名に対して繰り返し行われます。この処理をメソッドとしてまとめておき、必要な時に呼び出すようにしたものがMethod.javaです。
同じ処理が繰り返し行われる場合は、その処理をメソッドにまとめ、部品として扱うようにすることで、複数の記述の手間を省略でき、また、ソースコードが簡潔で読みやすくなります。また、後に修正が必要となった場合も、作業が少なくて済みます。メソッドの修正だけを行なえばよいからです。
それでは、次の項からこの2つのプログラムを実際に作成し、どのように違うかを確認してみましょう。
10.2.7 メソッドを使用しないプログラム
4人の生徒のテストの点数が合格点に達しているかどうかで異なるメッセージを表示するプログラムです。
これは、メソッドを作成せず、全ての処理をmainメソッドに記述しています。
① ソース・フォルダー :myproj_intro/src
② パッケージ :jp.co.f1.intro.ch10
③ 名前 :NoMethod
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる
➢ NoMethod.java
package jp.co.f1.intro.ch10; public class NoMethod { public static void main(String[] args) { // 点数を管理する変数の宣言と初期化 int pointA = 85; int pointB = 32; int pointC = 60; int pointD = 40; System.out.print("A君は、"); if (pointA >= 50) { System.out.println(pointA + "点なので合格です。"); } else { System.out.println(pointA + "点なので不合格です。"); } System.out.println(" - - - "); System.out.print("B君は、"); if (pointB >= 50) { System.out.println(pointB + "点なので合格です。"); } else { System.out.println(pointB + "点なので不合格です。"); } System.out.println(" - - - "); System.out.print("Cさんは、"); if (pointC >= 50) { System.out.println(pointC + "点なので合格です。"); } else { System.out.println(pointC + "点なので不合格です。"); } System.out.println(" - - - "); System.out.print("Dさんは、"); if (pointD >= 50) { System.out.println(pointD + "点なので合格です。"); } else { System.out.println(pointD + "点なので不合格です。"); } System.out.println(" - - - "); } }
実行結果
続けて、次のプログラムの作成を行って下さい。
10.2.8 メソッドを使用したプログラム
4人の生徒のテストの点数が、合格点に達しているかどうかで異なるメッセージを表示するプログラムで、処理内容は先ほどのNoMethod.javaと同じです。しかし今回は、共通する処理をメソッドに分離しています。
先ほどのNoMethod.javaとどのように違うのかを比較しながらコーディングして下さい。
① ソース・フォルダー :myproj_intro/src
② パッケージ :jp.co.f1.intro.ch10
③ 名前 :Method
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる
➢ Method.java
package jp.co.f1.intro.ch10; public class Method { static void checkPass(int point){ if(point >= 50){ System.out.println(point + "点なので合格です。"); }else{ System.out.println(point + "点なので不合格です。"); } System.out.println(" - - - "); } public static void main(String[] args) { // 点数を管理する変数の宣言と初期化 int pointA = 85; int pointB = 32; int pointC = 60; int pointD = 40; System.out.print("A君は、"); checkPass(pointA); System.out.print("B君は、"); checkPass(pointB); System.out.print("Cさんは、"); checkPass(pointC); System.out.print("Dさんは、"); checkPass(pointD); } }
実行結果
解説
4名の点数を格納するint型の変数を宣言し、それぞれの値で初期化しています。行番号が違いますが、どちらもmainメソッドの中に記述しています。
➢ NoMethod.java
➢ Method.java
その後、それぞれの生徒の名前、合否、境界線(- – -)の表示を行います。これらの処理を記述している部分は、NoMethod.javaでは13~19行目になります。
Method.javaでは、24、25行目で生徒の名前、合否、境界線の表示を行っています。この時に25行目で呼び出しているcheckPassメソッドの本体は、5~14行目に記述してあります。
NoMethod.javaの14~19行目とcheckPassメソッド内の7~12行目は、全く同じ処理をしています。但し、Method.javaではcheckPassメソッドに処理をまとめ、必要な時に呼び出すようにしています。2つのプログラムの構造については、前項で学んだとおりです。
➢ NoMethod.java
➢ Method.java
Method.javaの25行目のメソッドの呼び出しから5~14行目のcheckPassメソッドの処理の流れを詳しく説明します。
➢ Method.java
25行目でcheckPassメソッドを呼び出すことで、メソッド内の処理が行われます。実引数としてint型の変数pointAを渡しています。5行目で指定している引数の型と個数に一致します。
➢ Method.java
次にメソッド本体である5~14行目の処理が実行されます。
まず、5行目に設定した引数の値が入ります。25行目で変数pointAを引数に取ったので、その値である85が仮引数である変数pointに代入されます。これは、図 10.2.9をイメージして下さい。
また、このメソッドの戻り値はvoidと記述されているので、戻り値はありません。
➢ Method.java
図 10.2.9 : 次に、メソッド内の処理である7~12行目が実行されます。
図 10.2.10 : checkPassメソッド呼び出し時の値の受け渡し
if – else文では、条件式で「point >= 50」が判定されます。変数pointには引数に取った値85が代入されているので、「85 >= 50」となり、条件が満たされます。そのため、8行目が実行され、「85点なので合格です。」という文字列が表示されます。if文の条件式が成立するので、else文には入りません。if – else文を抜けます。
その後、12行目が実行され、境界線に見立てた文字列「- – -」が表示され、メソッド内の処理が終了します。
➢ Method.java
その後も、残りの3名分の処理を行うために何度もメソッドを呼び出しています。引数に取る値によって、if – else文で合格のメッセージが表示されるか、不合格のメッセージが表示されるかが変わります。
➢ Method.java
Method.javaの27~34行目は、NoMethod.javaだと以下の21~43行目にあたります。
➢ NoMethod.java
このように、メソッドを上手く利用することで、簡潔で読みやすいプログラムを作成することができます。また修正が容易なのでメンテナンス性も高くなります。もし、プログラムのなかに何度も同じ処理をしている部分があったら、その部分をメソッドとしてまとめることができないかどうかを考えてみましょう。