0
Help us understand the problem. What are the problem?

posted at

updated at

プログラミング未経験で新人研修でプログラミングをやらされている皆様へ(4)

本稿は、プログラミング未経験で新人研修でプログラミングをやらされている皆様へ(3)の続きです。

メソッドを作成して、重複を減らす

でさぁ、ここまでなんとなく書いてきたけど、System.out.println()って何なの? 未だに説明がないんだけど。……と、疑問をお持ちの皆様、ついにここで説明します。これはメソッドと呼ばれるもので、それを呼び出しているんです。

同じ処理を何回も書くのは苦痛……

こんな計算になんの意味があるのかは分かりませんが、「2と3と5と7と11と13の、それぞれを二乗した結果の合計を求めなさい」というお題のプログラムを考えてみてください。数字の増え方が一定ではないので(あと、配列をまだ勉強していないので)、forループは使用できません。だから、こんなプログラムになります。

class SumOfPrimeSquare {
    public static void main(String[] args) {
        int sum = 0;

        sum += 2 * 2;
        sum += 3 * 3;
        sum += 5 * 5;
        sum += 7 * 7;
        sum += 11 * 11;
        sum += 13 * 13;

        System.out.println(sum);
    }
}

あ、+=は、右辺の値を左辺の変数に足し合わせるという意味です。sum += 2 * 2;sum = sum + 2 * 2;と同じ結果になります。

で、このプログラムは、2 * 2と書くつもりが2 * 3とか書いちゃいそうで怖いです。だから、変数を使用して間違いが発生する可能性を減らしてみましょう。

class SumOfPrimeSquare {
    public static void main(String[] args) {
        int sum = 0;

        int x = 2;
        sum += x * x;

        x = 3;
        sum += x * x;

        x = 5;
        sum += x * x;

        x = 7;
        sum += x * x;

        x = 11;
        sum += x * x;

        x = 13;
        sum += x * x;

        System.out.println(sum);
    }
}

長いよ! 間違いが発生しづらくはなりましたが、同じ処理を何回も書くのが面倒くさくなってしまいました。xに値を設定して、その二乗を計算してsunに足し合わせるという処理は、毎回同じですもんね。こんなときは、メソッドが役に立ちます。

メソッドを作成する

実は今までも皆様はメソッドを作成していて、それはpublic static void main(String[] args) {}の部分です。mainの部分がメソッドの名前、括弧の中が引数、中括弧の中がメソッドの処理となります……と言われてもなんだかわからないので、具体的なコードで説明とさせてください。

class SumOfPrimeSquare {
    public static void main(String[] args) {
        int sum = 0;

        sum += square(2);  // squareメソッドを使用して、2の2乗を足す
        sum += square(3);
        sum += square(5);
        sum += square(7);
        sum += square(11);
        sum += square(13);

        System.out.println(sum);
    }

    // 2乗した結果を返すメソッド
    static int square(int x) {
        return x * x;
    }
}

今回作成したメソッドは、プログラムの以下の部分です。

static int square(int x) {
    return x * x;
}

メソッドの最初のstaticはとりあえずおまじないだと考えてください(後でクラスと一緒に説明します)。次のintは、メソッドで処理をした結果(メソッドの戻り値と呼びます)の型です。今回はintの値の2乗を計算するメソッドなので、メソッドで処理をした結果もintになりますから、intを指定します。squareはメソッドの名前で、処理内容が分かる名前を自由に付けてください。今回は、二乗を計算するメソッドなので、英訳してsquareにしました。

括弧の中は、メソッドの処理の中で必要となる変数(メソッドの引数と呼びます)を記述します。二乗するにはどの数を二乗するのかという情報が必要なので、int型のxという変数を書きました。変数なので、名前は何でも構いません。aでもnumberでも何でも分かりやすければ可。数学では関数の引数はxとすることが多いので、今回は名前をxにしてみました。

中括弧の中が処理です。x * xで二乗を計算して、で、計算した結果を関数の処理結果とするためにreturnしています。だから中括弧の中はreturn x * x;となったわけですね。

メソッドを呼び出す

メソッドを作成しただけでは意味がないので、作成したメソッドを利用しましょう。メソッドを利用することを「呼び出す」と言います。

で、メソッドを呼び出しているのは、sum += square(2);sum += square(3);の、square(2)square(3)の部分です。呼び出される側であるメソッドを作成したときにメソッドの戻り値の型や引数の型を定義したことを、理解力は低いけど記憶力は良いコンピューターは覚えています。だから、メソッドを呼び出すときは型の記述は不要。メソッド名(引数に代入したい値)とするだけでオッケーです。

square(2)とすると、squareメソッドの一番目の引数であるint xに2が代入されます。int x = 2;と同じ処理が実行されるわけですね。で、そのxを使用してx * xした結果がメソッドの戻り値としてreturnされるので、2の二乗の4になって、それをsum+=すれば、これで2の二乗を足し合わせる部分まで終了。あとは続けてsquare(3)square(5)と続けて処理をしていけば完了です。メソッドを使ったら、最初のプログラムより間違いの可能性が減って、2番目のプログラムよりも大分楽になったでしょ?

メソッド呼び出し時、引数へは値が「代入」される

……どうせならsum +=の部分もメソッドの処理に含めちゃえば楽になるんじゃね? このようにお考えの方もいらっしゃると思いますが、残念ながらそれはうまくいきません。実際にプログラムを作って試してみましょう。

class SumOfPrimeSquare {
    public static void main(String[] args) {
        int sum = 0;

        square(sum, 2);
        square(sum, 3);
        square(sum, 4);
        square(sum, 5);
        square(sum, 11);
        square(sum, 13);

        System.out.println(sum);
    }

    static void square(int sum, int x) {
        sum += x * x;
    }
}

メソッドは処理結果を返さなくても構いません。で、その場合は、メソッドの戻り値の型をvoidにします。で、足し合わされる数を表現するint sumと、二乗して足し合わせる数を表現するint xを引数にしてみました。

さて、このプログラムを実行すると……0が表示されてしまいます。あれ? sum +=しているのにどうして?

それは、メソッド呼び出しの際に、引数へは代入がなされるためです。以下のプログラムで考えてみてください。

class SumOfPrimeSquare {
    public static void main(String[] args) {
        int i = 0;
        int j = i;

        j += 1;

        System.out.println(i);
        System.out.println(j);
    }
}

int i = 0;で、変数iの値は0になります。int j = i;では、変数jiの値を代入しているので、jの値は0になります。で、その後、j += 1;で、jの値は1を足されて、0 + 1の結果である1になります。ここで重要なのは、変数jには変数iの「値」が代入されただけで、変数iそのものとは無関係であることです。だから、その後のSystem.out.println(i);ではj += 1;したこととは無関係で、変数iの値である0が表示され、System.out.println(j);では変数jの値である1が表示されます。

考えてみれば当たり前ですよね。代入がこのような動作になっていないと、int j = i + 1;と書いたときの動きが、わけわからなくなっちゃいますもん。

で、これは引数でも同じです。square(sum, 2)したときの動作は、squareメソッドの一番目の引数のsumに、呼び出し側のsum(同じ名前なので分かりづらいですけど、呼び出し側と呼び出される側では同じ名前でも別の変数になります。詳細は、次の章で説明するスコープまでお待ちください)の値を代入し、2番目の引数のxに2を代入しています。値が代入されただけなので、呼び出されたメソッドの中で引数のsumxを二乗した結果を足し合わせても、呼び出し側の変数sumの値は変化しません(先のプログラムで、j += 1;しても変数iに影響がなかったのと同じ)。

だから、呼び出し側の変数sumの値は0のまま変化せず、だから最後のSystem.out.println(sum);で0が表示されたというわけ。

なんでそんな面倒な作りになっているんだと感じた方がいらっしゃるかもしれませんけど、これは、そのような作りの方がプログラミングが楽になるためです。詳細は次の章でご説明しますが、とりあえずは、呼び出される側のメソッドの引数は、呼び出す時に指定した値や変数の値が代入されるだけなのだと覚えておいてください。

ともあれ、その動作を理解してしまえば、メソッドはとても便利です。メソッドを活用したプログラムを作成してみてください。お疲れさまでした。

……ごめんなさい。枕であげたSystem.out.println()について書くのを忘れていました。実はこれ、Javaを作った人が作成してくれたメソッドなんです。今回作成したsquare()メソッドよりちょっと中身は複雑ですけど、でも、同じメソッドなんですよ。我々は、今までSystem.out.println()でメソッドを呼び出して、画面への表示をしていたわけですな。

プログラミング未経験で新人研修でプログラミングをやらされている皆様へ(5)に続く予定です。

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
0
Help us understand the problem. What are the problem?