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

同じメソッドでも、渡す値が変われば結果も変わる。
引数を使えば、Javaの処理はもっと柔軟に動かせる。

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

メソッドに引数を渡すと、外から受け取った値に合わせて処理内容を変えられます。
たとえば、隊士の名前を設定する setName メソッドがあったとしても、渡す名前が 水月 なのか、炎真 なのかで、表示される結果は変わります。

鬼滅の刃でたとえると、同じ「隊士名を登録せよ」という命令でも、渡す名前が違えば、登録される隊士も変わるようなものです。

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

Sample4.java で使う基本の形

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

ファイル名:Sample4.java

class DemonSlayer
{
    String name;
    int stamina;

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

    void setStamina(int s)
    {
        stamina = s;
        System.out.println("体力を" + stamina + "にしました。");
    }

    void show()
    {
        System.out.println("隊士の名前は" + name + "です。");
        System.out.println("体力は" + stamina + "です。");
    }
}

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

        mizuki.setName("水月");
        mizuki.setStamina(100);
    }
}

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

要素役割
name隊士の名前を保存する
stamina隊士の体力を保存する
setName(String n)外から受け取った名前を name に入れる
setStamina(int s)外から受け取った体力を stamina に入れる
show()現在の名前と体力を表示する

ここで注目したいのは、setName と setStamina です。

void setStamina(int s)

void setStamina(int s)

このように、メソッド名の後ろの丸かっこの中に String n や int s が書かれています。
これが仮引数です。

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

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

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

mizuki.setName("水月");
mizuki.setStamina(100);

このとき、setName に渡している 水月 が実引数です。
setStamina に渡している 100 も実引数です。

呼び出し実引数メソッド側の仮引数結果
mizuki.setName("水月");水月nname に 水月 が入る
mizuki.setStamina(100);100sstamina に 100 が入る

鬼滅の刃でたとえると、司令役が隊士に対して、

「名前は水月として登録せよ」
「体力は100として記録せよ」

と命令しているイメージです。

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

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

mizuki.setName("炎真");
mizuki.setStamina(80);

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

隊士の名前を炎真にしました。
体力を80にしました。

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

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

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

mizuki.setStamina(100);

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

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

void setStamina(int s)
{
    stamina = s;
    System.out.println("体力を" + stamina + "にしました。");
}

ここで s が仮引数です。

処理の流れはこうです。

順番処理内容
1mizuki.setStamina(100); を実行する100 を渡す
2int s が 100 を受け取るs に 100 が入る
3stamina = s; を実行するstamina に 100 が入る
4体力を100にしました。と表示される結果が出る

鬼滅の刃でたとえると、100 という体力値を巻物に書いて隊士へ渡し、隊士側がその値を自分の体力欄に記録するような流れです。

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

mizuki.setStamina(100);
mizuki.setStamina(70);
mizuki.setStamina(120);

このように呼び出せば、s には順番に 100、70、120 が入ります。

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

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

↓クリックすると拡大表示されます。

この図が示していること

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

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

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

実引数には変数も使える

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

たとえば、次のように main メソッドの中で先に変数を用意しておきます。
Sample4.java を以下のように修正します。

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

class DemonSlayer
{
    String name;
    int stamina;

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

    void setStamina(int s)
    {
        stamina = s;
        System.out.println("体力を" + stamina + "にしました。");
    }

    void show()
    {
        System.out.println("隊士の名前は" + name + "です。");
        System.out.println("体力は" + stamina + "です。");
    }
}

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

        String slayerName = "水月";
        int slayerStamina = 100;

        mizuki.setName(slayerName);
        mizuki.setStamina(slayerStamina);
    }
}

実行結果

隊士の名前を水月にしました。
体力を100にしました。

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

String slayerName = "水月";

として、slayerName という変数に 水月 を入れています。

そして、

mizuki.setName(slayerName);

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

同じように、

int slayerStamina = 100;
mizuki.setStamina(slayerStamina);

では、slayerStamina の中に入っている 100 を setStamina に渡しています。

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

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

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

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

呼び出し側メソッド側実際に渡されるもの
slayerNamenslayerName の中にある 水月
slayerStaminasslayerStamina の中にある 100

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

mizuki.setName(slayerName);

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

void setName(String n)

名前が違っていても問題ありません。
なぜなら、Javaが見ているのは変数名をそろえることではなく、渡される値と型だからです。

鬼滅の刃でたとえると、司令部の巻物では 隊士名 と書かれていて、隊士側の記録欄では n と呼んでいるようなものです。
呼び名が違っても、渡される中身が 水月 であれば、正しく処理できます。

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

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

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

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

ファイル名:Sample5.java

class DemonSlayer
{
    String name;
    int stamina;

    void setNameStamina(String n, int s)
    {
        name = n;
        stamina = s;
        System.out.println("隊士の名前を" + name + "に、体力を" + stamina + "にしました。");
    }

    void show()
    {
        System.out.println("隊士の名前は" + name + "です。");
        System.out.println("体力は" + stamina + "です。");
    }
}

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

        String slayerName = "水月";
        int slayerStamina = 100;

        mizuki.setNameStamina(slayerName, slayerStamina);
    }
}

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

void setNameStamina(String n, int s)

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

仮引数受け取る内容
nString隊士の名前
sint隊士の体力

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

mizuki.setNameStamina(slayerName, slayerStamina);

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

順番実引数仮引数入る値
1slayerNamen水月
2slayerStaminas100

つまり、slayerName の中身が n に入り、slayerStamina の中身が s に入ります。

複数引数では順番が大切

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

void setNameStamina(String n, int s)

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

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

mizuki.setNameStamina(slayerName, slayerStamina);

鬼滅の刃でたとえると、隊士登録の巻物に、

  1. 名前
  2. 体力

という順番で記入欄があるようなものです。

名前の欄には名前を、体力の欄には体力を入れる必要があります。
順番がずれると、Javaは正しく受け取れません。

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

↓クリックすると拡大表示されます。

この図が示していること

この図では、setNameStamina(String n, int s) に対して、slayerName と slayerStamina の2つの実引数が渡される流れを示しています。

slayerName の値は n に入り、slayerStamina の値は s に入ります。

ここから分かるのは、複数の引数では、実引数と仮引数が左から順番に対応するということです。
引数が増えても基本の考え方は同じで、受け取る箱が増えただけだと考えると分かりやすくなります。

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

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

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

void setNameStamina(String n, int s)

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

mizuki.setNameStamina(slayerName, slayerStamina);

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

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

mizuki.setNameStamina(slayerName);

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

鬼滅の刃でたとえると、隊士登録に 名前 と 体力 の2項目が必要なのに、名前だけしか書かれていない状態です。
必要な情報が足りないため、登録を完了できません。

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

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

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

void setName(String n)

void setStamina(int s)

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

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

void show()
{
    System.out.println("隊士の名前は" + name + "です。");
    System.out.println("体力は" + stamina + "です。");
}

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

種類定義例呼び出し例使う場面
引数ありvoid setName(String n)mizuki.setName("水月");外から値を渡したいとき
引数ありvoid setStamina(int s)mizuki.setStamina(100);外から数値を渡したいとき
複数引数ありvoid setNameStamina(String n, int s)mizuki.setNameStamina(slayerName, slayerStamina);複数の値をまとめて渡したいとき
引数なしvoid show()mizuki.show();オブジェクトが持つ情報だけで処理できるとき

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

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

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

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

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

しかし、次のように仮引数 n で受け取る形にしておけば、

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

呼び出し側から好きな名前を渡せます。

mizuki.setName("水月");
mizuki.setName("炎真");
mizuki.setName("風音");

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

鬼滅の刃でたとえると、隊士登録の手順そのものは共通ですが、登録される隊士の名前は毎回変えられる、ということです。

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

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

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

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

メソッド役割
setName(String n)名前だけを設定する
setStamina(int s)体力だけを設定する
setNameStamina(String n, int s)名前と体力をまとめて設定する
show()現在の名前と体力を表示する

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

鬼滅の刃でたとえると、

メソッド隊士への命令
setName隊士名を登録せよ
setStamina体力を記録せよ
setNameStamina隊士名と体力をまとめて登録せよ
show現在の隊士情報を報告せよ

というイメージです。

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

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

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

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

鬼滅の刃でたとえると、同じ命令でも、渡す巻物の内容が変われば、隊士の状態や行動も変わります。

「名前を登録せよ」という命令に 水月 を渡せば水月になります。
「体力を設定せよ」という命令に 100 を渡せば体力は100になります。
「名前と体力をまとめて登録せよ」という命令なら、名前と体力を順番に渡します。

このように考えると、引数はメソッドに情報を渡すための大事なしくみだと分かります。
引数が使えるようになると、メソッドはただの処理のまとまりではなく、受け取った値に応じて柔軟に動く部品として使えるようになります。