Java超|引数で処理を変える方法

同じメソッドでも、渡す値が変われば結果も変わる。引数を使えば、悟空・ベジータ・悟飯の情報を同じしくみで柔軟に設定できます。

Javaのメソッドは、いつも同じ結果だけを出すものではありません。

メソッドに引数を渡すと、外から受け取った値に合わせて処理内容を変えられます。

たとえば、戦士の名前を設定する setName メソッドがあったとしても、渡す名前が 悟空 なのか、ベジータ なのか、悟飯 なのかで、設定される結果は変わります。

ドラゴンボールの世界観でたとえると、同じ「戦士名を登録せよ」という命令でも、渡す名前が変われば、登録される戦士も変わるようなものです。

メソッド名は同じでも、渡す値によって結果が変わる。
これが、引数を使う大きな意味です。

この記事では、引数で処理が変わるしくみを、サイヤ人戦士に名前・戦闘力・流派の印・流派名を渡して設定する流れとして整理していきます。

Sample4.java で使う基本の形

この記事では、前の記事で扱った Sample4.java を使って、引数で処理が変わるしくみを確認していきます。

ファイル名:Sample4.java

class Saiyan
{
    String name;
    int power;
    String styleMark;
    String styleName;

    void setName(String n)
    {
        name = n;
        System.out.println("戦士の名前を" + name + "にしました。");
    }

    void setPower(int p)
    {
        power = p;
        System.out.println("戦闘力を" + power + "にしました。");
    }

    void setStyleMark(String mark)
    {
        styleMark = mark;
        System.out.println("流派の印を「" + styleMark + "」にしました。");
    }

    void setStyleName(String style)
    {
        styleName = style;
        System.out.println("流派名を" + styleName + "にしました。");
    }

    void show()
    {
        System.out.println("戦士の名前は" + name + "です。");
        System.out.println("戦闘力は" + power + "です。");
        System.out.println("流派の印は「" + styleMark + "」です。");
        System.out.println("流派名は" + styleName + "です。");
    }
}

class Sample4
{
    public static void main(String[] args)
    {
        Saiyan goku = new Saiyan();

        goku.setName("悟空");
        goku.setPower(9000);
        goku.setStyleMark("亀");
        goku.setStyleName("亀仙流");
    }
}

このプログラムでは、Saiyan クラスに name、power、styleMark、styleName というフィールドがあります。

要素役割
name戦士の名前を保存する
power戦闘力を保存する
styleMark流派の印を保存する
styleName流派名を保存する
setName(String n)外から受け取った名前を name に入れる
setPower(int p)外から受け取った戦闘力を power に入れる
setStyleMark(String mark)外から受け取った流派の印を styleMark に入れる
setStyleName(String style)外から受け取った流派名を styleName に入れる
show()現在の名前、戦闘力、流派情報を表示する

ここで注目したいのは、setName、setPower、setStyleMark、setStyleName です。

void setName(String n)

void setPower(int p)

void setStyleMark(String mark)

void setStyleName(String style)

このように、メソッド名の後ろの丸かっこの中に String n、int p、String mark、String style が書かれています。

これが仮引数です。

仮引数は、メソッドが外から値を受け取るための箱です。

流派の表記を確認する

この記事では、流派を表す情報として styleMark と styleName を使います。

styleMark は、流派を短く表す印です。
styleName は、流派の正式な名前です。

styleMarkstyleName
亀仙流
鶴仙流
武泰斗流
カリン流
ピッコロ魔族流
神流(ナメック流)
惑星戦士流
北の界王流

Sample4.java では、悟空の流派を次のように設定しています。

フィールド設定値
styleMark
styleName亀仙流

つまり、goku.setStyleMark("亀"); で流派の印を設定し、goku.setStyleName("亀仙流"); で流派名を設定しています。

同じメソッドでも、渡す値で結果が変わる

Sample4.java では、main メソッドの中で次のように呼び出しています。

goku.setName("悟空");
goku.setPower(9000);
goku.setStyleMark("亀");
goku.setStyleName("亀仙流");

このとき、setName に渡している 悟空 が実引数です。
setPower に渡している 9000 も実引数です。
setStyleMark に渡している 亀 も実引数です。
setStyleName に渡している 亀仙流 も実引数です。

呼び出し実引数メソッド側の仮引数結果
goku.setName("悟空");悟空nname に 悟空 が入る
goku.setPower(9000);9000ppower に 9000 が入る
goku.setStyleMark("亀");markstyleMark に 亀 が入る
goku.setStyleName("亀仙流");亀仙流stylestyleName に 亀仙流 が入る

ドラゴンボールでたとえると、管理システムから悟空オブジェクトに対して、次のように命令しているイメージです。

命令渡す値
戦士名を登録せよ悟空
戦闘力を記録せよ9000
流派の印を登録せよ
流派名を登録せよ亀仙流

命令の形は同じでも、渡す内容が変われば、戦士の状態も変わります。

たとえば、次のように値を変えたとします。

goku.setName("ベジータ");
goku.setPower(8500);
goku.setStyleMark("惑");
goku.setStyleName("惑星戦士流");

この場合は、同じ setName、setPower、setStyleMark、setStyleName を使っていても、結果は変わります。

戦士の名前をベジータにしました。
戦闘力を8500にしました。
流派の印を「惑」にしました。
流派名を惑星戦士流にしました。

つまり、メソッドそのものは同じでも、渡す実引数が変われば、処理結果も変わるということです。

図:同じメソッドでも渡す値で結果が変わる

以下の条件でイラストを作成してください。

カラーイラスト、16:9横長。白と青を基調にした学習教材風デザイン。ドラゴンボール風のアニメ調。背景は未来的な戦闘データ管理ルーム。青いホログラム画面、スカウター風UI、コードパネルを配置する。

画面中央に大きく「同じメソッドでも、渡す値で結果が変わる」と表示する。

画面左にコードカードを2つ配置する。

1つ目のカードには次を表示する。

「goku.setPower(9000);」
「→ power = 9000」

2つ目のカードには次を表示する。

「goku.setPower(8500);」
「→ power = 8500」

画面右に「setPower(int p)」というメソッドカードを配置し、カード内に「p が受け取った値を power に設定」と表示する。

下部に小さな戦士アイコンを2つ配置する。
1つ目は悟空アイコンとして、ワインレッドの道着、右胸に「亀」の丸いマークを入れる。
2つ目はベジータアイコンとして、原作衣装に似せないサイヤ人の戦闘服風オリジナル衣装にし、「惑」のマークを入れる。

髪型と顔、特に目元は原作キャラクターに似すぎないよう、学習教材向けのオリジナル調にする。文字は読みやすく、背景やキャラクターと重ならないようにする。

この図が示していること

この図では、同じ setPower(int p) というメソッドに対して、9000 と 8500 という異なる実引数を渡しています。

メソッド名は同じでも、仮引数 p に入る値が変わるため、最終的に power に保存される値も変わります。

ここから分かるのは、メソッドは固定された結果だけを出すものではなく、受け取った値に応じて動きを変えられるということです。

仮引数は、実引数を受け取る箱

引数の流れは、次のように考えると分かりやすいです。

goku.setPower(9000);

この呼び出しでは、9000 が実引数です。

そして、メソッド側では次のように受け取ります。

void setPower(int p)
{
    power = p;
    System.out.println("戦闘力を" + power + "にしました。");
}

ここで p が仮引数です。

処理の流れはこうです。

順番処理内容
1goku.setPower(9000); を実行する9000 を渡す
2int p が 9000 を受け取るp に 9000 が入る
3power = p; を実行するpower に 9000 が入る
4戦闘力を9000にしました。と表示される結果が出る

ドラゴンボールでたとえると、9000 という戦闘力データをスカウターの登録画面から悟空オブジェクトへ送り、悟空側がその値を自分の戦闘力欄に記録するような流れです。

ここで大切なのは、p という仮引数の名前は同じでも、呼び出しごとに中へ入る値は変わることです。

goku.setPower(9000);
goku.setPower(7000);
goku.setPower(12000);

このように呼び出せば、p には順番に 9000、7000、12000 が入ります。

仮引数は、毎回新しく渡される実引数を受け取る箱だと考えると、かなり理解しやすくなります。

実引数には変数も使える

実引数には、文字列や数値をそのまま書くだけでなく、変数を使うこともできます。

たとえば、main メソッドの中で先に変数を用意しておきます。

ファイル名:Sample4.java(修正後)

class Saiyan
{
    String name;
    int power;
    String styleMark;
    String styleName;

    void setName(String n)
    {
        name = n;
        System.out.println("戦士の名前を" + name + "にしました。");
    }

    void setPower(int p)
    {
        power = p;
        System.out.println("戦闘力を" + power + "にしました。");
    }

    void setStyleMark(String mark)
    {
        styleMark = mark;
        System.out.println("流派の印を「" + styleMark + "」にしました。");
    }

    void setStyleName(String style)
    {
        styleName = style;
        System.out.println("流派名を" + styleName + "にしました。");
    }

    void show()
    {
        System.out.println("戦士の名前は" + name + "です。");
        System.out.println("戦闘力は" + power + "です。");
        System.out.println("流派の印は「" + styleMark + "」です。");
        System.out.println("流派名は" + styleName + "です。");
    }
}

class Sample4
{
    public static void main(String[] args)
    {
        Saiyan goku = new Saiyan();

        String warriorName = "悟空";
        int warriorPower = 9000;
        String warriorStyleMark = "亀";
        String warriorStyleName = "亀仙流";

        goku.setName(warriorName);
        goku.setPower(warriorPower);
        goku.setStyleMark(warriorStyleMark);
        goku.setStyleName(warriorStyleName);
    }
}

実行結果は次のようになります。

戦士の名前を悟空にしました。
戦闘力を9000にしました。
流派の印を「亀」にしました。
流派名を亀仙流にしました。

ここでは、setName に 悟空 と直接書いているわけではありません。

String warriorName = "悟空";

として、warriorName という変数に 悟空 を入れています。

そして、

goku.setName(warriorName);

と書くことで、warriorName の中に入っている値を setName に渡しています。

同じように、戦闘力や流派情報も変数を通して渡しています。

int warriorPower = 9000;
String warriorStyleMark = "亀";
String warriorStyleName = "亀仙流";

goku.setPower(warriorPower);
goku.setStyleMark(warriorStyleMark);
goku.setStyleName(warriorStyleName);

ここで大事なのは、メソッドに届くのは変数名そのものではなく、その変数の中身だということです。

呼び出し側の変数中身渡される先
warriorName悟空setName(String n)
warriorPower9000setPower(int p)
warriorStyleMarksetStyleMark(String mark)
warriorStyleName亀仙流setStyleName(String style)

変数を実引数に使うと、値をあらかじめ準備してからメソッドへ渡せます。

実引数の変数名と仮引数の名前は同じでなくてよい

少し混乱しやすいところですが、呼び出し側の変数名と、メソッド側の仮引数名は同じでなくてかまいません。

次の対応を見てください。

呼び出し側メソッド側実際に渡されるもの
warriorNamenwarriorName の中にある 悟空
warriorPowerpwarriorPower の中にある 9000
warriorStyleMarkmarkwarriorStyleMark の中にある 亀
warriorStyleNamestylewarriorStyleName の中にある 亀仙流

呼び出し側では warriorName という名前を使っています。

goku.setName(warriorName);

でも、受け取る側では n という名前です。

void setName(String n)

名前が違っていても問題ありません。

なぜなら、Javaが見ているのは変数名をそろえることではなく、渡される値と型だからです。

ドラゴンボールでたとえると、管理画面では 戦士名 と書かれていて、Saiyan クラス側の受け取り欄では n と呼んでいるようなものです。
呼び名が違っても、渡される中身が 悟空 であれば、正しく処理できます。

図:変数を実引数として渡す流れ

この図が示していること

この図は、実引数に変数を使った場合、メソッドへ渡されるのは変数名ではなく、変数の中身であることを示しています。

warriorName という変数名そのものが n に入るのではありません。
warriorName の中に入っている 悟空 が n に渡されます。

同じように、warriorPower の中身である 9000 が p に渡されます。

この図から分かることは、呼び出し側の変数名とメソッド側の仮引数名が違っていても、値と型が合っていれば正しく渡せるということです。

複数の引数を持つメソッド

引数は1つだけではありません。
メソッドには、2つ以上の引数を持たせることもできます。

たとえば、戦士の名前、戦闘力、流派の印、流派名を別々に設定するのではなく、1回のメソッド呼び出しでまとめて設定したい場合があります。

そのようなときは、複数の引数を持つメソッドを作ると便利です。

ファイル名:Sample5.java

class Saiyan
{
    String name;
    int power;
    String styleMark;
    String styleName;

    void setSaiyanData(String n, int p, String mark, String style)
    {
        name = n;
        power = p;
        styleMark = mark;
        styleName = style;

        System.out.println("戦士の名前を" + name + "に、戦闘力を" + power + "にしました。");
        System.out.println("流派の印を「" + styleMark + "」に、流派名を" + styleName + "にしました。");
    }

    void show()
    {
        System.out.println("戦士の名前は" + name + "です。");
        System.out.println("戦闘力は" + power + "です。");
        System.out.println("流派の印は「" + styleMark + "」です。");
        System.out.println("流派名は" + styleName + "です。");
    }
}

class Sample5
{
    public static void main(String[] args)
    {
        Saiyan goku = new Saiyan();

        String warriorName = "悟空";
        int warriorPower = 9000;
        String warriorStyleMark = "亀";
        String warriorStyleName = "亀仙流";

        goku.setSaiyanData(warriorName, warriorPower, warriorStyleMark, warriorStyleName);
    }
}

このプログラムでは、setSaiyanData というメソッドを作っています。

void setSaiyanData(String n, int p, String mark, String style)

このメソッドは、4つの仮引数を持っています。

仮引数受け取る内容
nString戦士の名前
pint戦闘力
markString流派の印
styleString流派名

呼び出し側では、次のように4つの実引数を渡しています。

goku.setSaiyanData(warriorName, warriorPower, warriorStyleMark, warriorStyleName);

このとき、値は左から順番に対応します。

順番実引数仮引数入る値
1warriorNamen悟空
2warriorPowerp9000
3warriorStyleMarkmark
4warriorStyleNamestyle亀仙流

つまり、warriorName の中身が n に入り、warriorPower の中身が p に入り、warriorStyleMark の中身が mark に入り、warriorStyleName の中身が style に入ります。

複数引数では順番が大切

複数の引数を使うときは、順番がとても大切です。

void setSaiyanData(String n, int p, String mark, String style)

この定義では、1番目に String、2番目に int、3番目に String、4番目に String を受け取る形になっています。

そのため、呼び出すときも次のように、名前、戦闘力、流派の印、流派名の順に渡します。

goku.setSaiyanData(warriorName, warriorPower, warriorStyleMark, warriorStyleName);

ドラゴンボールでたとえると、戦士登録カードに次の順番で記入欄があるようなものです。

順番登録欄
1名前
2戦闘力
3流派の印
4流派名

名前の欄には名前を、戦闘力の欄には戦闘力を、流派の印の欄には 亀 のような印を、流派名の欄には 亀仙流 のような正式名を入れる必要があります。

順番がずれると、意図した内容として受け取れなくなります。

図:複数の実引数は左から順番に渡される

この図が示していること

この図では、setSaiyanData(String n, int p, String mark, String style) に対して、warriorName、warriorPower、warriorStyleMark、warriorStyleName の4つの実引数が渡される流れを示しています。

warriorName の値は n に入ります。
warriorPower の値は p に入ります。
warriorStyleMark の値は mark に入ります。
warriorStyleName の値は style に入ります。

ここから分かるのは、複数の引数では、実引数と仮引数が左から順番に対応するということです。

引数が増えても基本の考え方は同じで、受け取る箱が増えただけだと考えると分かりやすくなります。

仮引数の数と実引数の数はそろえる

複数の引数を使うときは、仮引数の数と実引数の数をそろえる必要があります。

Sample5.java の setSaiyanData は、4つの仮引数を持っています。

void setSaiyanData(String n, int p, String mark, String style)

そのため、呼び出し側でも4つの値を渡します。

goku.setSaiyanData(warriorName, warriorPower, warriorStyleMark, warriorStyleName);

これは正しい呼び出しです。

一方で、次のように1つしか渡さない呼び出しはできません。

goku.setSaiyanData(warriorName);

setSaiyanData は4つの値を受け取る準備をしているのに、1つしか渡していないからです。

ドラゴンボールでたとえると、戦士登録に 名前、戦闘力、流派の印、流派名 の4項目が必要なのに、名前だけしか書かれていない状態です。

必要な情報が足りないため、登録を完了できません。

引数ありメソッドと引数なしメソッド

Sample4.java と Sample5.java には、引数ありのメソッドと引数なしのメソッドがあります。

たとえば、setName や setPower は引数ありです。

void setName(String n)

void setPower(int p)

これらは、外から値を受け取って処理します。

一方で、show は引数なしです。

void show()
{
    System.out.println("戦士の名前は" + name + "です。");
    System.out.println("戦闘力は" + power + "です。");
    System.out.println("流派の印は「" + styleMark + "」です。");
    System.out.println("流派名は" + styleName + "です。");
}

show は、外から新しい値を受け取らなくても動けます。
すでにオブジェクトが持っている name、power、styleMark、styleName を表示するだけだからです。

種類定義例呼び出し例使う場面
引数ありvoid setName(String n)goku.setName("悟空");外から名前を渡したいとき
引数ありvoid setPower(int p)goku.setPower(9000);外から数値を渡したいとき
引数ありvoid setStyleMark(String mark)goku.setStyleMark("亀");外から流派の印を渡したいとき
引数ありvoid setStyleName(String style)goku.setStyleName("亀仙流");外から流派名を渡したいとき
複数引数ありvoid setSaiyanData(String n, int p, String mark, String style)goku.setSaiyanData(warriorName, warriorPower, warriorStyleMark, warriorStyleName);複数の値をまとめて渡したいとき
引数なしvoid show()goku.show();オブジェクトが持つ情報だけで処理できるとき

外から情報を渡して動きを変えたいなら、引数あり。
今持っている情報だけで処理できるなら、引数なし。

この使い分けができると、メソッドの設計がかなり整理しやすくなります。

引数を使うと、メソッドを再利用しやすくなる

引数の便利なところは、同じメソッドを何度も再利用できることです。

たとえば、setName メソッドの中に 悟空 という名前を直接書いてしまうと、そのメソッドは悟空専用になってしまいます。

しかし、次のように仮引数 n で受け取る形にしておけば、呼び出し側から好きな名前を渡せます。

void setName(String n)
{
    name = n;
    System.out.println("戦士の名前を" + name + "にしました。");
}

呼び出し側では、次のように変えられます。

goku.setName("悟空");
goku.setName("ベジータ");
goku.setName("悟飯");

同じ setName を使っていても、渡す値によって結果を変えられます。

ドラゴンボールでたとえると、戦士登録の手順そのものは共通ですが、登録される戦士の名前は毎回変えられる、ということです。

この考え方があるから、メソッドは柔軟な部品として使えます。

メソッドの役割を分けるとコードが読みやすくなる

引数を使うと、メソッドの役割を分けやすくなります。

Sample4.java と Sample5.java では、次のように役割を分けています。

メソッド役割
setName(String n)名前だけを設定する
setPower(int p)戦闘力だけを設定する
setStyleMark(String mark)流派の印だけを設定する
setStyleName(String style)流派名だけを設定する
setSaiyanData(String n, int p, String mark, String style)名前、戦闘力、流派の印、流派名をまとめて設定する
show()現在の戦士情報を表示する

このように分けると、コードを読むときに何をしているのかが分かりやすくなります。

ドラゴンボールでたとえると、次のような命令になります。

メソッド戦士への命令
setName戦士名を登録せよ
setPower戦闘力を記録せよ
setStyleMark流派の印を記録せよ
setStyleName流派名を記録せよ
setSaiyanData戦士情報をまとめて登録せよ
show現在の戦士情報を報告せよ

メソッドは、処理をただまとめるだけではありません。
どんな値を受け取り、どんな役割を果たすのかをはっきりさせることで、プログラム全体が読みやすくなります。

引数で処理を変えるときの大切な感覚

引数で処理を変えるときは、次の感覚を持つと理解しやすいです。

ポイント内容
同じメソッドでも結果は変わる渡す実引数が変われば、仮引数に入る値も変わる
実引数には変数も使える変数名ではなく、中に入っている値が渡される
仮引数名と実引数側の変数名は違ってよい名前ではなく、値と型が大切
複数の引数も使えるカンマで区切って複数の値を渡せる
複数引数は順番が大切左から順番に仮引数へ入る
仮引数と実引数の数をそろえる受け取る箱の数と渡す値の数を合わせる
引数なしメソッドもある外から値を受け取らず、今持っている情報だけで動く

ドラゴンボールでたとえると、同じ命令でも、渡す戦士データの内容が変われば、オブジェクトの状態も変わります。

「名前を登録せよ」という命令に 悟空 を渡せば、name は 悟空 になります。
「戦闘力を設定せよ」という命令に 9000 を渡せば、power は 9000 になります。
「流派を設定せよ」という命令に 亀 と 亀仙流 を渡せば、styleMark は 亀、styleName は 亀仙流 になります。

このように考えると、引数はメソッドに情報を渡すための大事なしくみだと分かります。

引数が使えるようになると、メソッドはただの処理のまとまりではなく、受け取った値に応じて柔軟に動く部品として使えるようになります。