関数

今回の内容

今回は結果を起動元に返すメソッドについて紹介します。これまでのメソッドは値を渡して起動することはできても、メソッドの中で計算したデータを起動元に返すことはできませんでした。これが値を返すようになると、「消費税を計算して値を返す」などの関数のようなプログラムの部品を作成できるようになります。

図: 値を返すメソッド

なお、今回の講義でメソッドの基本的な内容は終わりです。メソッドはJavaのプログラミングで非常に重要な役割を果たしますので、是非習得してください。次回以降の授業では、プログラムを読みやすくするために、メソッドを多用しながら新しい内容を紹介していく予定です。

今回の作業

今回の例題、練習問題、課題は以下のパッケージに作成してください。

パッケージの名前
j1.lesson05

クラスの作成方法については、「クラスを作成する」を参照してください。

結果を返すメソッド

return文

値を返す簡単なメソッドについてみてみましょう。

リスト: Add
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package j1.lesson05;
 
import javax.swing.JOptionPane;
 
public class Add {
 
    public static void main(String[] args) {
        new Add().start();
    }
 
    void start() {
        String input1 = JOptionPane.showInputDialog("1つ目の整数を入力");
        String input2 = JOptionPane.showInputDialog("2つ目の整数を入力");
        int a = Integer.parseInt(input1);
        int b = Integer.parseInt(input2);
        int result = add(a, b);
        JOptionPane.showMessageDialog(null, "合計は" + result);
    }
 
    int add(int a, int b) {
        return a + b;
    }
}

これは「2つの引数の和を返すメソッド」ですが、これまでのメソッドと2か所違う部分があります。

リスト: (メソッドの宣言)
int add(int a, int b) {
    return a + b;
}

1つ目は、void add(…)ではなくint add(…)としている点です。voidの代わりに指定したintは「このメソッドは整数(int)の値を返す」ということを表しています。そして2つ目は、returnから始まる命令です。returnは「メソッドの処理を終了し、起動元に値を返す」という効果を持ちます。返す値は例のようにreturnの右側に指定します。ここでは、2つの引数の和をreturnに指定していますので、起動元にはこの値がそのまま渡されることになります。

なお、returnから始まる命令をreturn文と呼び、値を返すメソッドはかならず何らかの値を返さなければならないため、ブロックには最低1つのreturn文が必要です。また、ブロックには今まで通り複数の命令を書けますが、return文を処理するとそこでメソッドの実行が終了するため、それ以降に命令を書けません。

returnで返した値を起動側で受け取るには、変数と同じように値の代わりに利用します。この例では、変数resultは先ほどのメソッドがreturnで返した値、つまりaとbの和を記憶させています。

リスト: Add(メソッドの起動)
int result = add(a, b);
図: 値の受渡し

なお、値を返すメソッドは整数以外の値を返すこともできます。その場合には、メソッドの宣言時に整数(int)以外の型を指定してやり、return文ではそれぞれの値を返します。まとめると次のような形式で値を返すメソッドを宣言できます。

int <メソッドの名前>(<仮引数の一覧>) {
    <命令>
    return <整数>;
}
double <メソッドの名前>(<仮引数の一覧>) {
    <命令>
    return <実数>;
}
String <メソッドの名前>(<仮引数の一覧>) {
    <命令>
    return <文字列>;
}

練習: 値を返すメソッド

作成するクラスの名前
Average

下記のプログラムを書き換えて、3つの実数を受け取って、それらの平均を表示するようにしなさい。ただし、平均を計算する部分はaverageという名前のメソッドで行うこと。

リスト: Average
package j1.lesson05;
 
import javax.swing.JOptionPane;
 
public class Average {
 
    public static void main(String[] args) {
        new Average().start();
    }
 
    void start() {
        String input1 = JOptionPane.showInputDialog("1つ目の実数を入力");
        String input2 = JOptionPane.showInputDialog("2つ目の実数を入力");
        String input3 = JOptionPane.showInputDialog("3つ目の実数を入力");
        double a = Double.parseDouble(input1);
        double b = Double.parseDouble(input2);
        double c = Double.parseDouble(input3);
        double result = ___________;
        JOptionPane.showMessageDialog(null, "平均は" + result);
    }
 
    ________ average(double a, double b, double c) {
        double total = a + b + c;
        _____________
    }
}

複数のreturn文

次の例を見てみましょう。

リスト: Absolute
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package j1.lesson05;
 
import javax.swing.JOptionPane;
 
public class Absolute {
 
    public static void main(String[] args) {
        new Absolute().start();
    }
 
    void start() {
        String input = JOptionPane.showInputDialog("実数を入力");
        double number = Double.parseDouble(input);
        JOptionPane.showMessageDialog(null, "絶対値は" + getAbsolute(number));
    }
 
    double getAbsolute(double number) {
        if (number < 0.0) {
            return -number;
        }
        else {
            return number;
        }
    }
}

これは実数の絶対値を返すメソッドgetAbsoluteを宣言していますが、中にはreturn文が2つ書かれています。このように、if文を使って分岐するプログラムでは、それぞれの分岐先でreturn文を書くこともできます。分岐先でreturn文を処理した場合には、メソッドの処理はそこで終了し、以降の命令を処理せずに起動元に値が返されます。

ただし、次のようなメソッドは作成できません。

リスト: Absolute(エラー)
double getAbsolute(double number) {
    if (number < 0.0) {
        return -number;
    }
}

これは仮引数のnumberに記憶させた値が0.0以上だった際に、return文が処理されずにメソッド内の処理が完了してしまいます。これではメソッドの起動元に値を返せませんので、Javaのプログラムとしては正しくありません。if文でどのように分岐しても、かならずreturn文が処理されるように書きましょう。

練習: 様々な値を返すメソッド

作成するクラスの名前
Grading

下記のプログラムを書き換えて、整数の得点を入力し、範囲ごとに成績を表示するプログラムを作成しなさい。

範囲や成績を表す文字列は特に指定しないが、思いつかない場合は次のようにすること。

得点 成績
90点以上 A+
80点以上90点未満 A
70点以上80点未満 B
60点以上70点未満 C
60点未満 D
リスト: Grading
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
package j1.lesson05;
 
import javax.swing.JOptionPane;
 
public class Grading {
 
    public static void main(String[] args) {
        new Grading().start();
    }
 
    void start() {
        String input = JOptionPane.showInputDialog("得点を入力");
        int score = Integer.parseInt(input);
        JOptionPane.showMessageDialog(null, "成績は" + getGrade(score));
    }
 
    String getGrade(int score) {
 
    }
}

論理値を返すメソッド

次は、メソッドの起動をif文の条件式として利用する例を紹介します。if文の条件式には「成立する」「成立しない」といういずれかに処理されますが、このような値を「論理値」と呼びます。

リスト: Rating
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package j1.lesson05;
 
import javax.swing.JOptionPane;
 
public class Rating {
 
    public static void main(String[] args) {
        new Rating().start();
    }
 
    void start() {
        String input = JOptionPane.showInputDialog("評価値を入力(1-5)");
        int rate = Integer.parseInt(input);
        if (isInvalid(rate)) {
            JOptionPane.showMessageDialog(null, "不正な評価値です");
        }
    }
 
    boolean isInvalid(int rate) {
        if (rate < 1 || rate > 5) {
            return true;
        }
        else {
            return false;
        }
    }
}

論理値はbooleanという型で表し、「成立する」ということをtrue (真)で、「成立しない」ということをfalse (偽)で表します。このtrue, falseはそれぞれ論理リテラルといい、整数や文字列リテラルと同様にプログラム中に書けます。

リスト: 論理値を返すメソッド
boolean isInvalid(int rate) {
    if (rate < 1 || rate > 5) {
        return true;
    }
    else {
        return false;
    }
}

論理値を返すこのようなメソッドは、次のようにif文の条件部の中から起動できます。

リスト: 論理値を返すメソッドの起動
if (isInvalid(rate)) {
    JOptionPane.showMessageDialog(null, "不正な評価値です");
}
図: 論理値の受渡し

次に、先ほどと逆の論理値を返す例についてみてみましょう。今回はisInvalidではなくisValidなので、成立しない場合に「不正な評価値です」と表示します。

リスト: Rating2
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package j1.lesson05;
 
import javax.swing.JOptionPane;
 
public class Rating2 {
 
    public static void main(String[] args) {
        new Rating2().start();
    }
 
    void start() {
        String input = JOptionPane.showInputDialog("評価値を入力(1-5)");
        int rate = Integer.parseInt(input);
        if (!isValid(rate)) {
            JOptionPane.showMessageDialog(null, "不正な評価値です");
        }
    }
 
    boolean isValid(int rate) {
        if (rate < 1 || rate > 5) {
            return false;
        }
        else {
            return true;
        }
    }
}

このプログラムでは、isValidというメソッドを起動する際に、手前に ! という演算子を指定しています。これは「条件式の結果を反転する」という演算子で、論理否定とも呼ばれています。メソッドisValidは評価値が正当である場合にtrue (成立する)を返し、不正である場合にfalse (成立しない)を返すので、そのまま利用すると表示が逆になってしまいます。そのため、条件式の先頭に ! をつけて成立と不成立を逆転させているというわけです。

リスト: 論理否定
if (!isValid(rate)) {
    JOptionPane.showMessageDialog(null, "不正な評価値です");
}

まとめると、if文の条件式で利用するメソッドは、論理値を返すように宣言します。そのとき、メソッド内のreturn文では、論理値のリテラルであるtrue (真, 成立する)、false (偽, 成立しない)を返します。

boolean <メソッドの名前>(<仮引数の一覧>) {
    <命令>
    return <trueまたはfalse>;
}

また、条件式の結果を反転する ! という演算子についても紹介しました。これは、条件式の先頭に指定すると、成立と不成立が逆になります。

入力を処理するメソッド

今回最後の例として、入力を処理するメソッドについて紹介します。

リスト: InputMethod
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package j1.lesson05;
 
import javax.swing.JOptionPane;
 
public class InputMethod {
 
    public static void main(String[] args) {
        new InputMethod().start();
    }
 
    void start() {
        int rate = getInput();
        if (!isValid(rate)) {
            JOptionPane.showMessageDialog(null, "不正な評価値です");
        }
    }
 
    int getInput() {
        String input = JOptionPane.showInputDialog("評価値を入力(1-5)");
        int rate = Integer.parseInt(input);
        return rate;
    }
 
    boolean isValid(int rate) {
        if (1 <= rate && rate <= 5) {
            return true;
        }
        else {
            return false;
        }
    }
}

「入力ダイアログを表示して、整数に変換して返す」というだけのメソッドなので特に新しい要素はありません。

リスト: 入力された値を返すメソッド
int getInput() {
    String input = JOptionPane.showInputDialog("評価値を入力(1-5)");
    int rate = Integer.parseInt(input);
    return rate;
}

しかし、このように「ひとかたまりの処理」をメソッドに切り出すことで、分かりやすいプログラムが書けるようになります。下記は「入力されたレートが不正なら、メッセージを表示」と読めると思います。

リスト: ひとかたまりの処理を利用するメソッド
void start() {
    int rate = getInput();
    if (isInvalid(rate)) {
        JOptionPane.showMessageDialog(null, "不正な評価値です");
    }
}

今後の授業では、小さなプログラムであっても、理解しやすい単位でメソッドに分解して説明をしようと思います。

練習: 入力を処理するメソッド

作成するクラスの名前
QuizMethod

下記のプログラムを修正し、入力した整数を返すメソッドを宣言しなさい。showQuizメソッドからは、そのメソッドを利用してユーザから入力させること。

リスト: QuizMethod
package j1.lesson05;
 
import javax.swing.JOptionPane;
 
public class QuizMethod {
 
    public static void main(String[] args) {
        new QuizMethod().start();
    }
 
    void start() {
        showQuiz("10 + 20 = ?", 30);
        showQuiz("リンゴの色は? (1) 青 (2) 赤", 2);
        showQuiz("うるう年の1年の日数は?", 366);
    }
 
    void showQuiz(String message, int correct) {
        String input = JOptionPane.showInputDialog(message);
        int answer = Integer.parseInt(input);
        if (answer == correct) {
            JOptionPane.showMessageDialog(null, "正解です");
        }
        else {
            JOptionPane.showMessageDialog(null, "不正解です");
        }
    }
}

まとめ

今回は、値を返すメソッドについて紹介しました。メソッドの宣言時に返す値の型を指定し、メソッドのブロックでreturn文を使って起動元に返す値を指定します。

<戻り値の型> <メソッドの名前>(<仮引数の一覧>) {
    <命令>
    return <起動元に渡す値>;
}

return文はメソッドのどこに書いてもかまいませんが、return文が処理された瞬間にそのメソッドは処理を終了して指定された値を起動元に返します。このため、値を返すメソッドではif文などで分岐してもかならずreturn文を通るようにプログラミングする必要があります。

値を返すメソッドは、プログラムの中でリテラルの代わりに使用できます。

リスト: 値を返すメソッド
...
    int score = add(50, 70) / 2;
...
int add(int a, int b) {
    return a + b;
}

戻り値の種類については、整数 (int)、実数 (double)、文字列 (String)に加え、今回初めて紹介した論理値 (boolean)などを指定できます。それぞれのメソッドでは、return文を利用して対応する値を起動元に返してやります。

int <メソッドの名前>(<仮引数の一覧>) {
    <命令>
    return <整数>;
}
double <メソッドの名前>(<仮引数の一覧>) {
    <命令>
    return <実数>;
}
String <メソッドの名前>(<仮引数の一覧>) {
    <命令>
    return <文字列>;
}
boolean <メソッドの名前>(<仮引数の一覧>) {
    <命令>
    return <trueまたはfalse>;
}

論理値を返すメソッドは、if文の条件式を書くところで起動できます。起動先のメソッドがtrueを返せば条件が成立したとみなされ、falseを返せば条件が成立しなかったとみなされます。また、先頭に ! をつけることでtrueとfalseを反転させられます。

if (<メソッドの名前>(<実引数の一覧>)) {
    <成立する場合の命令>
}
if (!<メソッドの名前>(<実引数の一覧>)) {
    <成立しない場合の命令>
}

以上が今回のまとめです。メソッドが値を返せるようになったことで、「プログラムの部品化」がさらにやりやすくなったと思います。「値を入力して整数に変換する」などのプログラム中から何度も利用する処理は、ひとまとめにしてメソッドとして宣言するとプログラム全体が読みやすくなります。