【本サイトではGoogleアドセンス、または、アフィリエイト広告を利用しています。】
メソッドとは?
メソッドとは、一連の処理を1つにまとめたものです。
例えば、「歯を磨く」という言葉の中には、
以下のような行動がすべて含まれます。
・歯ブラシを洗う
・歯磨き粉を歯ブラシにつける
・歯を歯ブラシで磨く
・コップに水を入れる
・水で口をゆすぐ
・タオルで口を拭く
・歯ブラシ、コップを洗って片付ける
これをプログラムにした時、「歯を磨く」というコードだけで
一連の処理を簡易的に呼び出せるようにしたもの、それがメソッドです。
変数はプログラム全体から見ると1つの部品ですが、
メソッドもプログラム全体から見ると中規模の部品と言えます。
また、メソッドは関数とも呼ばれます。Excelで使う関数と考え方は同じです。
メソッドについては、こちらで基本的な考え方を説明していますので、
あわせて読んでみてください。
Excelの関数についてはこちらで説明しています。
メソッドの書き方(定義方法)
メソッドの書き方は以下です。
修飾子 戻り値の型 メソッド名(型1 引数名1, 型2 引数名2, …) { 処理 return 戻り値; }
プログラムで例に書くと以下のような感じです。
private static int add(int a, int b) {
int result = a + b;
return result;
}
これは、足し算した結果を返すメソッドです。
では、修飾子、引数、戻り値について説明していきます。
修飾子とは?
修飾子とは、変数、メソッド、クラスといった各部品の性質や、
それらを扱うことのできる範囲を定義する為のコードです。
主によく使う種類としては以下ですが、使い方がわかるまでは
「private」と「static」の2つを続けて書くということで覚えておきましょう。
これは、インスタンス化(クラスの説明をする時にお話します)することなく使えて、
同じクラスからのみ呼び出せるメソッドという意味です。
修飾子 | 説明 |
---|---|
private | 同じクラスからのみ呼び出せる。 |
protected | 同じパッケージ、または、サブクラスからのみ呼び出せる。 |
public | どこからでも呼び出せる。 |
abstract | 抽象クラス、抽象メソッドとして扱う。 |
static | インスタンス化せずに使える。 |
final | 代入する値や、実行する処理の上書きを禁止する。 |
引数とは?
引数とは、メソッド内の処理で使う値のことです。
例えば、足し算の処理を書く場合、2つの数字が必要になります。
また、「足し算をする」という動きは決まっていますが、
実際に使う値についてはメソッドを定義する時点で決まっていません。
そして、足す値は、メソッド側が決めるのではなく、
メソッドを呼び出す側の都合で動的に変わるものなので、
どんな値が来ても足せる状態にしておく必要があります。
その為、処理に必要な値を想定して、
引数と言う形で変数を使って定義しておくのです。
電子レンジは「温める」という機能を持っていますが、
「何を」温めるのかまであらかじめ決まってませんよね?
この例で言えば、電子レンジがメソッドで、
中に入れる食べ物が引数になります。
戻り値とは?
戻り値とは、メソッドが行った処理の結果です。
例えば、足し算メソッドでは「足し算の答え」が戻り値になります。
そして、1つのメソッドに定義できる戻り値は1つだけです。
これは、返す値が1つということではなく、変数として1つということです。
なので、複数の値を保持できる配列やコレクションなども指定できます。
戻り値を受け取るのは、メソッドを呼び出す側になるので、
どんな型で結果値を戻すのかあらかじめ決めておく必要があります。
voidとは?
メソッドの中で処理行った時に、戻り値が必ずあるわけではありません。
例えば、単純にメッセージを出力するだけのメソッドであれば
呼び出して中の処理を実行するだけです。
このように、戻り値を使わないメソッドについては、
戻り値がないという意味としてメソッドに「void」を付加します。
ということで、mainメソッドにvoidがついているのも
そういう意図があった為です。
メソッドの使い方(サンプルコード)
ここまでの内容を踏まえて、
メソッドの使い方をサンプルコードで見ていきましょう。
引数で与えられた2つの値を足した結果を
戻り値として返すメソッドを用意しました。
package example;
public class Example {
public static void main(String[] args) {
int a = 1;
int b = 2;
int result = 0;
// 足し算メソッドを呼び出して結果をresultに代入する
result = add(a, b);
System.out.println("答えは「" + result + "」です。");
}
// 足し算メソッド
private static int add(int a, int b) {
int result = a + b;
return result;
}
}
実行結果は以下です。
答えは「3」です。
足し算を行うメソッドaddをmainメソッド側で呼び出し、
結果を出力する流れです。しっかり足し算できていますね!
と、メソッドの定義と基本的な使い方はここまでですが、
ここでもう1点注目して欲しいところは、main側に定義している変数aとb、
add側の引数として定義している変数aとbです。
よく見ると、変数resultもmain側とadd側の両方に定義されています。
1つのプログラムの中で同じ名前の変数が定義できるのはなぜでしょう?
これは、変数を扱うことのできる範囲に関係しています。
この有効範囲のことをスコープと呼びます。
Javaでは、メソッド内で定義した変数は、メソッド内でのみ扱うことができます。
つまり、名前は同じでも、お互いの有効範囲には存在しておらず、
プログラムの実行単位としても別の扱いになるので、このような定義ができるのです。
mainのresultと、addのresultはまったく別の変数であることを覚えておいてください。
ちなみに、addの引数にresultを定義すると、
addのローカル変数resultとスコープが重なる(どちらもaddの中で使う変数になる)
ので、エラーとなり実行できません。
引数の型による動きの違い|プリミティブ型変数と参照型変数
では、もう1つ、応用です。
変数の型には、プリミティブ型と、参照型の2種類があります。
プリミティブ型については以下でも説明していますが、
intやlongなどのプリミティブ型以外に、
配列やクラスなどを型として定義したものを参照型変数と呼びます。
メソッドの引数としてそれぞれを使った場合、
以下の例のように動きが異なってくるので覚えておきましょう!
まずは、プリミティブ型の例です。
package example;
public class Example {
public static void main(String[] args) {
int result = 1;
// resultの値を書き換える
changeValue(result);
System.out.println("結果は「" + result + "」です。");
}
// 値を書き換えるメソッド
private static void changeValue(int result) {
result = 3;
// 戻り値なし
return;
}
}
実行結果は以下です。
結果は「1」です。
あれあれ?値を書き換えたのに、結果が「1」のままです。
バ、バグってる?!
はい、これは、起こしがちなミスです。バグあるあるです。
変数をメソッドに渡して、渡した先で書き換えてるから、
中身が書き換わったような気になりますが、実際の動きは違います。
先ほどのお話の通り、メソッド内に定義した変数はメソッド内でのみ有効です。
つまり、changeValueメソッドの処理が終了した時点で、
changeValueメソッド内の変数resultの役目は終わるのです。
mainメソッド内の変数resultは、changeValueメソッドの処理の中に
登場してくることはないので、changeValueメソッドが動いたことに関わらず、
値は初期化時に代入された「1」のままとなります。
では、次に参照型の例を見てみましょう。
先ほどの例を使って、変数resultを配列にしてみました。
package example;
public class Example {
public static void main(String[] args) {
int[] result = {1};
// resultの値を書き換える
changeValue(result);
System.out.println("結果は「" + result[0] + "」です。");
}
// 値を書き換えるメソッド
private static void changeValue(int[] result) {
result[0] = 3;
// 戻り値なし
return;
}
}
実行結果は以下です。
結果は「3」です。
今度はしっかり書き換えられています!
え?メソッド内の変数はメソッドないで完結するんじゃないの?
その通りです!でも、参照型は少し違うんです。
これは、変数の特徴の違いにあります。
参照型変数は、値そのものを持つのではなく、
値の入ったデータの場所(アドレス)を値として持っています。
つまり、参照型は変数に入っている値を見に行く時、
プリミティブ型よりもワンステップ多いのです。
プリミティブ型のように、変数に直接紐づいている値を書き換えるのではなく、
参照型では、持っているアドレスの先にある値を書き換えることになる為、
changeValueメソッドの処理が終了した後、changeValue内の変数resultが破棄されても、
アドレスが消えるだけで、アドレスの先にある値はそのまま残っているわけです。
このように、プリミティブ型と参照型で動きが変わってくるので、
しっかり内容を理解して使い分けできるようにしましょう!
戻り値を使って処理結果を複数返す方法
メソッドが返せる変数は1つですが、値は1つとは限りません。
処理を行って、複数の結果を返したい時などあると思います。
そんな時は、戻り値の型に、配列やコレクションを使えば実現できます。
サンプルとして、複数の足し算を別々に行って
2つの結果を配列に入れるメソッドをご紹介します!
package example;
public class Example {
public static void main(String[] args) {
int a = 1;
int b = 2;
int c = 3;
int d = 4;
// 複数の足し算を実行した結果を代入する
int[] result = addMulti(a, b, c, d);
System.out.println("1つ目の結果は「" + result[0] + "」です。");
System.out.println("2つ目の結果は「" + result[1] + "」です。");
}
// 複数の足し算を行った結果を返すメソッド
private static int[] addMulti(int a, int b, int c, int d) {
int[] result = new int[2];
result[0] = a + b;
result[1] = c + d;
return result;
}
}
実行結果は以下です。
1つ目の結果は「3」です。
2つ目の結果は「7」です。
aとb、cとdが別々に足された結果がmainメソッドでうまく出力されていますね!
複数足し算した結果を、配列resultに順番に格納して戻り値として返しています。
戻り値を使わずに処理結果を複数返す方法
先ほどの応用として、戻り値を使わずに
複数の処理結果を返す方法にチャレンジしてみましょう!
サンプルコードは以下です。
package example;
public class Example {
public static void main(String[] args) {
int a = 1;
int b = 2;
int c = 3;
int d = 4;
int[] result = new int[2];
// 複数の足し算を実行する
addMulti(a, b, c, d, result);
System.out.println("1つ目の結果は「" + result[0] + "」です。");
System.out.println("2つ目の結果は「" + result[1] + "」です。");
}
// 複数の足し算を行うメソッド
private static void addMulti(int a, int b, int c, int d, int[] result) {
result[0] = a + b;
result[1] = c + d;
return;
}
}
実行結果は以下です。
1つ目の結果は「3」です。
2つ目の結果は「7」です。
こちらもmainメソッドでうまく出力されていますね!
今回は、足し算の結果を、引数で渡した配列resultに入れるようにしました。
先ほどのお話の通り、配列は参照型なので、
戻り値は使わずとも値は書き換えられたまま保持されます。
このように、戻り値を使わずとも、値を参照型変数に保持しておくことで
呼び出し元へ結果を返す方法もあります。
コレクションと呼ばれるクラスを使えばもっときれいに処理が書けるので、
余裕がある人、コレクションのことを知っている人はチャレンジしてみましょう!
まとめ
Javaのメソッドについて、以下説明しました。
- メソッドについて
- メソッドの書き方
- メソッドの使い方
- プリミティブ型と参照型を引数にした時の動きの違い
- 戻り値を使って複数の結果を返す方法
- 戻り値を使わず複数の結果を返す方法
何度も同じ処理を書くと、プログラムの可読性も下がって、
修正する時にはいくつも同じ個所を修正することになったり、
増えれば増えるほどメンテナンスが大変になってくるので、
メソッドを使ってなるべく1つの処理にまとめるクセをつけていきましょう!