第13講・STEP 02

戻り値で関数を作る

戻り値の型を変えると、メソッドの使い方も変わります。今回は、3で割り切れるかを調べるメソッドを改造し、結果の文字列を返すようにしてみましょう。引数を入力、戻り値を出力と考える「関数」の感覚もつかんでいきます。

文字列を返す

 前回、引数に渡された値が3で割り切れるかどうかを調べるメソッドを作りました。

 3で割り切れれば戻り値としてtrueを返し、割り切れなければfalseを返すようにし、そのメソッドをif文の条件式の中に入れることで、割り切れる場合と割り切れない場合とに分岐させて結果を出力するプログラムでした。

 こんなやつです。↓

ReturnTest.java

public class ReturnTest{
   public static void main(String[] args){
      int a = 23165247;
      if( isMultipleOf3(a) ){
         System.out.println(a + "は3で割り切れます");
      }else{
         System.out.println(a + "は3で割り切れません");
      }
   }
   public static boolean isMultipleOf3(int n){
      boolean result;
      result = ( n % 3  == 0 );
      return result;
   }
}

 一応、思った通りには動いているのですが、もっと戻り値の仕組みの理解を深める為にも、今回はこのclassを改造したいと思います。

 これが元々のisMultipleOf3メソッドの定義部分です。

ReturnTest.java

public static boolean isMultipleOf3(int n){
      boolean result;
      result = ( n % 3  == 0 );
      return result;
}

 しつこいようですが、このメソッドは引数に渡された値が3で割り切れればtrueを返し、割り切れなければfalseを返すメソッドです。

 前回はその戻り値のboolean(trueかfalse)を使って、mainメソッド内でif文で分岐させて「3で割り切れます」とかっていう文字列を作らせていましたが、今回はこのメソッド自体に結果の文字列も生成する機能を持たせようと思います。

 つまり、trueかfalseを返すのではなく、「15は3で割り切れます」みたいな文字列(String型の値)を返すようにします。

Stringを返すメソッド

 戻り値に文字列を返すので、戻り値の型はStringです。前回のは戻り値の型がbooleanだったので、書き換えます。

ReturnTest.java

public static String isMultipleOf3(int n){
      
}

 これで、戻り値としてStringを返すメソッドですよ、という定義になりました。

 メソッド名が「isMultipleOf3」です。実はこの「is○○○」というメソッド名は戻り値がboolean型のメソッドにつける形なんです(慣習みたいなものです)。戻り値がbooleanじゃないのにこのメソッド名はちょっとおかしいのですが、ここではこのまま行かせて下さい。

 メソッドの中身は一から作りなおします。まず戻り値に返す文字列を保持するString型変数resultMessageを宣言します(空の文字列で初期化)。

ReturnTest.java

public static String isMultipleOf3(int n){
     String resultMessage = "";
     
}

 そのString変数resultMessageに、if文を使って、3で割り切れるかどうかの文字列を入れましょう。

ReturnTest.java

public static String isMultipleOf3(int n){
     String resultMessage = "";
     if(n % 3 == 0){
          resultMessage = n + "は3で割り切れます";
     }else{
          resultMessage = n + "は3で割り切れません";
     }
}

 そして、その文字列を入れたresultMessageをreturnします。

ReturnTest.java

public static String isMultipleOf3(int n){
     String resultMessage = "";
     if(n % 3 == 0){
          resultMessage = n + "は3で割り切れます";
     }else{
          resultMessage = n + "は3で割り切れません";
     }
     return resultMessage;
}

 これでisMultipleOf3メソッドの定義はOKです。引数に渡された値(n)が3で割り切れれば、「nは3で割り切れます」という文字列を戻り値として返し、引数に渡された値(n)が3で割り切れなければ「nは3で割り切れません」という文字列を戻り値として返します。

 さて、文字列を返してくるメソッドをどう使えばいいでしょうか?こうしましょう。

ReturnTest.java

public class ReturnTest{
     public static void main(String[] args){
           System.out.println(isMultipleOf3(123456789));
     }
     
     public static String isMultipleOf3(int n){
          String resultMessage = "";
          if(n % 3 == 0){
               resultMessage = n + "は3で割り切れます";
          }else{
               resultMessage = n + "は3で割り切れません";
          }
          return resultMessage;
     }
}

 printlnメソッドの引数に、isMultipleOf3メソッドをぶち込みました。こんな場所ででも呼ばれるとreturnされた値に置き換わります。

 つまり、isMultipleOf3メソッドが返した文字列がprintlnメソッドにより画面に出力されるわけです。上記の例では123456789を渡しています。これを実行すると、

実行結果
123456789は3で割り切れます

 バッチリですね。

戻り値の型によって変わるそのメソッドの使い方

 前回はisMultipleOf3メソッドはtrueかfalseを返すメソッドだったので、mainメソッド内でその結果から文字列を作る作業をする必要がありましたが、今回の改造版では文字列を返すメソッドにしたことで、このようにmainメソッドでは、単純にその戻り値の文字列を出力させるだけで済みます。

 そのおかげで何回も連続して使いやすくなりました。こんなこともできます。

ReturnTest.java

public class ReturnTest{
     public static void main(String[] args){
          System.out.println(isMultipleOf3(123456789));
          System.out.println(isMultipleOf3(15));
          System.out.println(isMultipleOf3(22));
          System.out.println(isMultipleOf3(987654321));
     }
     
     public static String isMultipleOf3(int n){
          String resultMessage = "";
          if(n % 3 == 0){
               resultMessage = n + "は3で割り切れます";
          }else{
               resultMessage = n + "は3で割り切れません";
          }
          return resultMessage;
     }
}

 これを実行すると、

実行結果
123456789は3で割り切れます
15は3で割り切れます
22は3で割り切れません
987654321は3で割り切れます

こうなります。

 というわけで、booleanを返すバージョンと、Stringを返すバージョンと作ってみました。

 booleanを返すバージョンは、その戻り値を条件分岐に使えるので非常にいろんな使い方ができます。が、もし結果を文字列として表示する処理をmainメソッド内に書こうと思えば、mainメソッド自体がif文だらけになってしまいます。

 一方、Stringを返すバージョンは、表示用の文章ができあがっているので、上記の例のように続けて何回も出力しやすいというメリットがあります。もちろん、返された文字列を変数に保存したり、他の文字列と連結したりすることもできます。ただし、割り切れるかどうかを条件分岐に使いたいなら、booleanで返す方がそのまま使えて便利です。

 どちらが良いとか悪いとかではなく、自分で戻り値を返すメソッドを作る時には、何を戻り値として返せばそのメソッドを便利に使えるか?また、返ってきた値をどういう風に利用するか?をよく考えて作る必要があります。

 まあこの辺は書いてみて、失敗して、修正して・・というのを繰り返すことで、だんだん分かってくると思うので、とにかく書いてみることだと思います。

戻り値と関数

 メソッドは、「関数」と呼ばれることもあります。

 関数というのは要は何かを入力したら何かが出力されるその法則のことです。函数とも書きます。函ってのはいわゆる箱です。箱に何かを入れると、何かが出て来るというイメージですね。

引数を受け取り、処理の結果を返す

引数(入力)15

メソッド3で割り切れるか調べる

戻り値(出力)「15は3で割り切れます」

 引数が入力で、戻り値が出力と考えると、今回のメソッドは関数のように捉えられます。ここでいう「出力」は、画面への表示ではなく、呼び出し元へ値を返すことです。

 ( )の中に値を入れる、つまり関数に値を渡すと出力値に置き換わるわけです。

数学で習った f(x) = 2x も、まさに「受け取った値を2倍して返す」という関数の定義です。Javaのメソッドで書くと、こんな形になります。

f(int x) {
    return x * 2;
}

ここに f(3) と実際の値を渡すと、xに3が入り、3 × 2の結果である6が返ります。つまり、f(3)という式が6に置き換わるわけです。

値を渡すと、計算結果に置き換わる
f(3)3 × 26

 数学で習う関数は入力も出力も数値でしたが、プログラミングではintを受け取ってStringを返すとか、Stringを受け取ってbooleanを返すとか自分で決めることができます。

 慣れてくると自由自在です。関数を上手くつなげて組み上げていけば、少々複雑な処理でもシンプルなコードとして表現することができます。

 こういった関数的な感覚が身につけば、コードを読むのも書くのも、格段にレベルアップします!

 引数と戻り値は、メソッドをいわゆる関数として扱う為の重要な仕組みですのでしっかり理解しましょう。

※プログラミングでは、メソッドを広い意味で関数と呼ぶこともあります。ただし、メソッドは外部の状態を変更したり、同じ引数でも違う値を返したりする場合があり、数学の関数といつも同じ性質を持つわけではありません。

コンパイラによる型チェック

 コンパイルエラーというのを経験したことはありますよね?

 例えば、;(セミコロン)が抜けていたり、変数名のつづりが間違っていたりした時などになるアレです。誰もがやってしまうミスです。

 コンパイルエラーというのは、プログラムを実行する前に一通りコンパイラがソースコードをチェックして、「このままプログラムを実行したらおかしなことになるよ!」というエラー箇所を見つけてくれているわけです。

 戻り値は、実はコンパイラによる重要なチェック項目の1つです。

 前回のisMultipleOf3メソッドは、戻り値としてbooleanを返しました。

 boolean型として定義したisMultipleOf3メソッドが、正常に処理を終えて値を返すなら、その値はbooleanです。
 
 戻り値の型がbooleanと決まっているからこそ、if文の条件式としてこのメソッドを使うことが許されるんです。

ReturnTest.java

if(isMultipleOf3(5)){ }

 一方、今回書いたisMultipleOf3メソッドの戻り値はStringですので、もしif文の条件式にそのまま入れてしまうと、コンパイルエラーになります。

ReturnTest.java

if(isMultipleOf3(5)){ }  //コンパイルエラー

 コンパイラはプログラムを実行するまでもなくすぐに気づきます。if文の条件式の中にStringが入っているようなソースコードは実行できない!って。このバージョンの戻り値の型がStringと決まっているからです。

 このようにJavaのコンパイラはプログラム実行前に、全てのメソッドについて戻り値の型を厳密にチェックすることで、ソースコードに辻褄の合わない箇所がないか見つけられるようになっています。

 メソッドの定義時に戻り値の型(あるいはvoid)を書くのは、正常に値を返すならbooleanですよ!とかこのメソッドは何も戻り値を返しませんよ!と約束しているわけですね。

public static boolean methodA(int n){ return n % 3 == 0; }

↑戻り値は絶対にboolean型

public static int methodB(int n){ return n; }

↑戻り値は絶対にint型

public static void methodC(int n){ }

↑戻り値は返さない(void)

 これで、引数と戻り値を使うメソッドの基本を一通り学びました。次は「オブジェクトって何?」に進みます。mainメソッドの引数について振り返りたい方は、補足の「コマンドライン引数って何?」も読んでみてください。

目次へ

質問・コメント

読み込み中

この記事についての質問や、学習して気づいたことをお寄せください。

コメントを書く

投稿フォームを準備しています。

コメントと一緒に公開される名前です。
3,000文字以内。パスワードなどの個人情報は書き込まないでください。

コメントは送信後すぐに公開されます。

この記事のコメント

旧サイトに寄せられたコメントも当時の投稿内容のまま掲載しています。現在の記事では変更している内容や、旧環境についてのやり取りも含まれます。

コメントを読み込んでいます。