引数は、呼び出し元のメソッドから呼び出したメソッドに、データを受け渡したいという要求をかなえる仕組みでした。 逆に、呼び出されたメソッドが処理した結果を呼び出し元に受け渡したい、という場合もあります。 これをかなえる仕組みが、戻り値です。
1: /* 2: * AiShow01.java 3: * Created on 2011/12/14 4: * Copyright(c) 2011 Yoshiaki Matsuzawa, Shizuoka University. All rights reserved. 5: */ 6: 7: /* 8: * 相性占いプログラム 9: */ 10: public class AiShow01 { 11: 12: public static void main(String[] args) { 13: AiShow01 main = new AiShow01(); 14: main.run(); 15: } 16: 17: void run() { 18: int aishow = judge("木村拓哉", "工藤静香"); 19: System.out.println("相性は" + aishow + "です"); 20: } 21: 22: int judge(String name1, String name2) { 23: int x = name1.hashCode() + name2.hashCode(); 24: x = x % 100; 25: return x; 26: } 27: }
ここ をクリックすると、プログラムをダウンロードできます。
戻り値ありメソッドの定義の仕方は、次の通りです。
[戻り値の型] [メソッド名]([引数の型] [仮引数名]){ return [戻り値]; }
戻り値ありメソッドの呼び出し方は、次の通りです(引数ありメソッドと同じです)。
[メソッド名]([実引数]);
戻り値は他の教科書では返り値と呼ばれていたりします。元々の英語「return value」の訳は定まっていないように思われます。 昔,僕がたくさんの教科書を調べたかぎりでは,「戻り値」,「返り値」,「リターン値」が各1/3くらいずつ分布していました。
先週使った「void」は「戻り値がない」という意味なのでした。
1: /* 2: * AiShow01.java 3: * Created on 2011/12/14 4: * Copyright(c) 2011 Yoshiaki Matsuzawa, Shizuoka University. All rights reserved. 5: */ 6: 7: /* 8: * 相性占いプログラム 9: * String版 10: */ 11: public class AiShow02 { 12: 13: public static void main(String[] args) { 14: AiShow02 main = new AiShow02(); 15: main.run(); 16: } 17: 18: void run() { 19: String aishow = judge("木村拓哉", "工藤静香"); 20: System.out.println("相性は" + aishow + "です"); 21: } 22: 23: String judge(String name1, String name2) { 24: int x = name1.hashCode() + name2.hashCode(); 25: x = x % 100; 26: String text = ""; 27: if (x > 80) { 28: text = "ばっちり"; 29: } else { 30: text = "そこそこ"; 31: } 32: return text; 33: } 34: }
ここ をクリックすると、プログラムをダウンロードできます。
1: /* 2: * AiShow01.java 3: * Created on 2011/12/14 4: * Copyright(c) 2011 Yoshiaki Matsuzawa, Shizuoka University. All rights reserved. 5: */ 6: 7: /* 8: * 相性占いプログラム 9: * String版,途中でreturnを書いて脱出 10: */ 11: public class AiShow02d { 12: 13: public static void main(String[] args) { 14: AiShow02d main = new AiShow02d(); 15: main.run(); 16: } 17: 18: void run() { 19: String aishow = judge("木村拓哉", "工藤静香"); 20: System.out.println("相性は" + aishow + "です"); 21: } 22: 23: String judge(String name1, String name2) { 24: int x = name1.hashCode() + name2.hashCode(); 25: x = x % 100; 26: if (x > 80) { 27: return "ばっちり"; 28: } else { 29: return "そこそこ"; 30: } 31: } 32: }
ここ をクリックすると、プログラムをダウンロードできます。
戻り値ありメソッドでは、return文を書いたところでメソッドの出力は決まり、メソッドの処理を抜けます。 したがって、return文の後に命令を書いても、実行されることはありません(「この文に制御が移ることはありません」というエラーが出ます)。
次のプログラムは、boolean(真偽値型)を使ったプログラムです。真偽値型はtrueまたはfalseの二値のどちらかが入る型です。
1: /* 2: * AiShow01.java 3: * Created on 2011/12/14 4: * Copyright(c) 2011 Yoshiaki Matsuzawa, Shizuoka University. All rights reserved. 5: */ 6: 7: /* 8: * 相性占いプログラム 9: * boolean版,途中でreturnを書いて脱出 10: */ 11: public class AiShow03 { 12: 13: public static void main(String[] args) { 14: AiShow03 main = new AiShow03(); 15: main.run(); 16: } 17: 18: void run() { 19: boolean aishow = judge("木村拓哉", "工藤静香"); 20: if (aishow == true) { 21: System.out.println("相性ばっちり!"); 22: } else { 23: System.out.println("努力次第..."); 24: } 25: } 26: 27: boolean judge(String name1, String name2) { 28: int x = name1.hashCode() + name2.hashCode(); 29: x = x % 100; 30: if (x > 80) { 31: return true; 32: } else { 33: return false; 34: } 35: } 36: 37: }
ここ をクリックすると、プログラムをダウンロードできます。
戻り値のあるプログラムの多段呼び出しももちろん可能です。
1: 2: /* 3: * AiShow01.java 4: * Created on 2011/12/14 5: * Copyright(c) 2011 Yoshiaki Matsuzawa, Shizuoka University. All rights reserved. 6: */ 7: 8: /* 9: * 相性占いプログラム 10: * 多段呼び出し + if文の中に命令 11: */ 12: public class AiShow03d { 13: 14: public static void main(String[] args) { 15: AiShow03d main = new AiShow03d(); 16: main.run(); 17: } 18: 19: void run() { 20: if (judge("木村拓哉", "工藤静香")) { 21: System.out.println("相性ばっちり!"); 22: } else { 23: System.out.println("努力次第..."); 24: } 25: } 26: 27: boolean judge(String name1, String name2) { 28: if (countAishow(name1, name2) > 80) { 29: return true; 30: } else { 31: return false; 32: } 33: } 34: 35: int countAishow(String name1, String name2) { 36: int x = name1.hashCode() + name2.hashCode(); 37: x = x % 100; 38: return x; 39: } 40: }
ここ をクリックすると、プログラムをダウンロードできます。
if文やwhile文の条件節には最終的に真偽値型の値が入ればよいという約束になっているので、真偽値型を戻り値に持つメソッドを直接書くことも出来ます。
引数は、複数指定することができますが、戻り値は必ずひとつです。 複数の戻り値を戻したい場合,配列,リストやクラス等を使ってデータを合成し,一つのデータの形にする必要があります。
メソッドを使って西暦和暦変換プログラムを構造化してみましょう.
はじめに,以下に構造化されていない西暦和暦変換プログラムを示します.
1: import java.util.Scanner; 2: 3: /** 4: * 西暦和暦変換プログラム(メソッドなし) 5: * 6: * @author オブプロ例題 7: * @version 1.0 8: */ 9: public class ConvertYearApplication1 { 10: 11: public static void main(String[] args) { 12: ConvertYearApplication1 main = new ConvertYearApplication1(); 13: main.run(); 14: } 15: 16: // 西暦を和暦に変換する 17: public void run() { 18: Scanner scanner = new Scanner(System.in); 19: 20: {// アプリケーションの開始を知らせる 21: System.out.println("西暦和暦変換プログラムを開始します"); 22: } 23: 24: {// 西暦を和暦に変換する 25: int year; 26: String japaneseYear; 27: 28: {// 西暦を入力する 29: System.out.println("西暦を入力してください"); 30: year = scanner.nextInt(); 31: } 32: 33: {// 西暦を和暦に変換する 34: if (year >= 1989) { 35: japaneseYear = "平成" + (year - 1988); 36: } else if (year >= 1926) { 37: japaneseYear = "昭和" + (year - 1925); 38: } else { 39: japaneseYear = "不明"; 40: } 41: } 42: 43: {// 変換結果を出力する 44: System.out.println(year + "年は" + japaneseYear + "年です."); 45: } 46: } 47: 48: {// アプリケーションの終了を知らせる 49: System.out.println("西暦和暦変換プログラムを終了します"); 50: } 51: } 52: }
ここ をクリックすると、プログラムをダウンロードできます。
メソッドを使って構造化された,西暦変換プログラムの完全版を読んでみましょう。
1: import java.util.Scanner; 2: 3: /** 4: * 西暦和暦変換プログラム(2レベルをメソッド化) 5: * 6: * @author オブプロ例題 7: * @version 3.0 8: */ 9: public class ConvertYearApplication3 { 10: 11: public static void main(String[] args) { 12: ConvertYearApplication3 main = new ConvertYearApplication3(); 13: main.run(); 14: } 15: 16: // 西暦を和暦に変換する 17: public void run() { 18: showTitle(); 19: convertYear(); 20: showEndTitle(); 21: } 22: 23: // 西暦を和暦に変換する 24: void convertYear() { 25: int year = inputYear(); 26: String japaneseYear = convertToJapaneseYear(year); 27: showResult(year, japaneseYear); 28: } 29: 30: // 西暦を入力する 31: int inputYear() { 32: Scanner scanner = new Scanner(System.in); 33: System.out.println("西暦を入力してください"); 34: int year = scanner.nextInt(); 35: return year; 36: } 37: 38: // 西暦を和暦に変換する 39: String convertToJapaneseYear(int year) { 40: String japaneseYear; 41: if (year >= 1989) { 42: japaneseYear = "平成" + (year - 1988); 43: } else if (year >= 1926) { 44: japaneseYear = "昭和" + (year - 1925); 45: } else { 46: japaneseYear = "不明"; 47: } 48: return japaneseYear; 49: } 50: 51: // 変換結果を出力する 52: void showResult(int year, String japaneseYear) { 53: System.out.println(year + "年は" + japaneseYear + "年です."); 54: } 55: 56: // アプリケーションの開始を知らせる 57: void showTitle() { 58: System.out.println("西暦和暦変換プログラムを開始します"); 59: } 60: 61: // アプリケーションの終了を知らせる 62: void showEndTitle() { 63: System.out.println("西暦和暦変換プログラムを終了します"); 64: } 65: 66: }
ここ をクリックすると、プログラムをダウンロードできます。
本節では、ユーザから底と指数の入力を受け取り、累乗を計算するプログラムの例を利用して、メソッドの単体テストの作り方について説明します。
メソッドをテストするのに,いちいち入力していたのでは手間がかかりますし,どのテストをやったのかを忘れてしまいます. さらには,プログラムを一行だけ修正したとしても,どの箇所が動かなくなるかは予測できないため,全てのテストをやり直す必要があります. したがって,テストはテストプログラムを作って自動化するのがよいです.具体的には,次のプログラムのように列挙して呼び出し,出力すると良いでしょう.
1: import java.util.Scanner; 2: 3: /* 4: * プログラム名:累乗計算プログラム 5: * 作成者: MegumiAraki 6: * 作成日: Tue Dec 04 12:28:06 JST 2007 7: */ 8: public class Power01 { 9: 10: // 起動処理 11: public static void main(String[] args) { 12: Power01 main = new Power01(); 13: main.run(); 14: } 15: 16: public void run(){ 17: System.out.println("calculatePower(" + 2 + ", " + 2 + ") = " + calculatePower(2, 2)); 18: System.out.println("calculatePower(" + 2 + ", " + 3 + ") = " + calculatePower(2, 3)); 19: System.out.println("calculatePower(" + 2 + ", " + 4 + ") = " + calculatePower(2, 4)); 20: System.out.println("calculatePower(" + 3 + ", " + 3 + ") = " + calculatePower(3, 3)); 21: } 22: 23: // 累乗を計算する 24: int calculatePower(int base, int exponent) { 25: int power = 1;// 累乗数の初期値を、数の0乗(1)に設定する 26: 27: // 累乗を計算する 28: int i = 0; 29: while (i < exponent) { 30: power = power * base; 31: i++; 32: } 33: 34: return power; 35: } 36: 37: }
ここ をクリックすると、プログラムをダウンロードできます。
テストの表示部分が冗長で,変更が大変です.テストはメソッドにしましょう.
1: import java.util.Scanner; 2: 3: /* 4: * プログラム名:累乗計算プログラム 5: * 作成者: MegumiAraki 6: * 作成日: Tue Dec 04 12:28:06 JST 2007 7: */ 8: public class Power02 { 9: 10: // 起動処理 11: public static void main(String[] args) { 12: Power02 main = new Power02(); 13: main.run(); 14: } 15: 16: public void run(){ 17: test(2,2); 18: test(2,3); 19: test(2,4); 20: test(3,3); 21: } 22: 23: void test(int base, int exp) { 24: System.out.println("calculatePower(" + base+ ", " + exp + ") = " + calculatePower(base, exp)); 25: } 26: 27: // 累乗を計算する 28: int calculatePower(int base, int exponent) { 29: int power = 1;// 累乗数の初期値を、数の0乗(1)に設定する 30: 31: // 累乗を計算する 32: int i = 0; 33: while (i < exponent) { 34: power = power * base; 35: i++; 36: } 37: 38: return power; 39: } 40: 41: }
ここ をクリックすると、プログラムをダウンロードできます。
Power02のプログラムでもテストできていますが,答えが合っているかを毎回目視で確認する必要があります.プログラムに答え(「期待値」といいます)を書いておき,照合結果も出力できるといいですね!
1: import java.util.Scanner; 2: 3: /* 4: * プログラム名:累乗計算プログラム 5: * 作成者: MegumiAraki 6: * 作成日: Tue Dec 04 12:28:06 JST 2007 7: */ 8: public class Power03 { 9: 10: // 起動処理 11: public static void main(String[] args) { 12: Power03 main = new Power03(); 13: main.run(); 14: } 15: 16: public void run(){ 17: test(2, 2, 4); 18: test(2, 3, 8); 19: test(2, 4, 16); 20: test(3, 3, 27); 21: } 22: 23: void test(int base, int exp, int expected) { 24: int answer = calculatePower(base,exp); 25: String result = ""; 26: if(answer == expected){ 27: result = "PASS"; 28: }else{ 29: result = "FAIL"; 30: } 31: System.out.println("calculatePower(" + base + ", " + exp + ") = " + answer + ", 判定: " + result); 32: } 33: 34: // 累乗を計算する 35: int calculatePower(int base, int exponent) { 36: int power = 1;// 累乗数の初期値を、数の0乗(1)に設定する 37: 38: // 累乗を計算する 39: int i = 0; 40: while (i < exponent) { 41: power = power * base; 42: i++; 43: } 44: 45: return power; 46: } 47: 48: }
ここ をクリックすると、プログラムをダウンロードできます。
年齢を計算する次のメソッドを作り,テストしてください. (以下,「テストする」とは,メインのプログラム(run()メソッド)から一回以上そのメソッドを呼ぶプログラムを書くことを意味する)
int getAge(int year){...}
yearは西暦で生まれ年を入力する引数で,今年の年齢を戻り値として出力する.(今年だけ使えればよい)
ファイル名は「HowOld.java」とすること.
税込み価格を計算する次のメソッドを作り,テストしてください.
int getWithTax(int withoutTax){...}
withoutTaxは税抜きの価格を入力する引数で,消費税込の価格を戻り値として出力する.(日本で,今年だけ使えればよい)
ファイル名は「ConsumptionTax.java」とすること.
勝率を計算する次のメソッドを作り,テストしてください.
int getWinningRate(int win, int lose){...}
winは勝数, loseは敗数をそれぞれ入力する引数で,勝率(単位%)を戻り値として出力する.(小数第一位以下切り捨て,もしくは四捨五入のいずれかでよい)
ファイル名は「WinningRate.java」とすること.
BMIを計算する次のメソッドを作り,テストしてください. (以下,「テストする」とは,メインのプログラム(run()メソッド)から一回以上そのメソッドを呼ぶプログラムを書くことを意味する)
double bmi(double height, double weight){...}
heightは身長,weightは体重を入力する引数で,BMI値を戻り値として出力する.
ファイル名は「BMI2.java」とすること.
1からnまでの総和(1からnまでの数を全部足した数)を計算する次のメソッドを作り,テストしてください.
int sum(int n){...}
nはいくつまでの総和を求めるか入力する引数で,計算された総和を戻り値として出力する.
ファイル名は「Summation.java」とすること.
最小値と最大値を考慮してランダムな数値を作りだす以下のメソッドを作り,テストしてください.
int makeRandom(int min, int max){...}
minは最小値,maxは最大値を入力する引数で,生成されたランダムな数(最小値から最大値の間に入ること!)を戻り値として出力する.
ファイル名は「MyRandom.java」とすること.
じゃんけんの判定をする次のメソッドを作り,テストしてください.
int jankenJudge(int hand1, int hand2){...}
hand1はplayer1の手(0-グー, 1-チョキ, 2-パー),hand2はplayer2の手(数字の割り当てはplayer1と同じ)を表現する引数で, player1からみた結果(1-勝ち,0-あいこ, (-1)-負け)を戻り値として出力する.
ファイル名は「Janken.java」とすること.
まず次のメソッドを作ってください。このメソッドは,コイン投げをシミュレートし,二分の一の確率でtrueを戻します。
boolean flip(){...}
次に,次のメソッドを作ってください。このメソッドは引数で与えられたn回flipメソッドを呼び,表が出た回数を数えて戻り値とします。
int simulate(int n){...}
最後に,このメソッドをテストし,実際の確率を計算してみてください。(できる人は,試行回数が増えるにつれて 1/2に近くなることを表現する出力を考えてみよう。)
ファイル名は「Coin.java」とすること.