Java:メソッド
1学習の目的
- 処理をメソッドに分けられるようになる。長くなった main を役割ごとに切り分け、読みやすく変更しやすいプログラムにできるようになる。
- 基本型と配列で引数の渡り方が違うことを理解する。メソッドの中で値を変えたとき、呼び出し元に影響するかどうかが決まる。
2基礎解説
| 部分 | 書き方 | 意味 |
|---|---|---|
| 戻り値の型 | static int add(…) | 返す値の型 |
| 戻り値なし | static void show(…) | 何も返さない |
| 引数 | add(int a, int b) | 受け取る値 |
| 返す | return a + b; | 結果を返す |
- メソッドは「戻り値の型 名前(引数) { … }」の形。main から呼ぶメソッドには static を付ける(理由はJV08で分かる)。
- 戻り値がないなら void。画面に出力するだけのメソッドは void でよい。値を返すなら return が必須。
- 同じ名前で引数が違うメソッドを作れる(オーバーロード)。calc(int) と calc(int, int) は別のメソッドとして扱われる。
- ⚠ 基本型は「値のコピー」、配列は「場所」が渡る。メソッド内で int を変えても呼び出し元は変わらないが、配列の中身を変えると呼び出し元も変わる。
- 1つのメソッドは1つの仕事に絞る。「税込価格を計算する」「一覧を表示する」のように役割を明確にすると、名前も付けやすく再利用しやすくなる。
現場使用例:税込計算、入力値の検証、データの整形、共通処理の切り出し。同じコードを2回書きそうになったら、メソッドにする合図。
public class Main {
// 戻り値あり
static int add(int a, int b) {
return a + b;
}
// 戻り値なし(void)
static void greet(String name) {
System.out.println(name + "さん、こんにちは");
}
// オーバーロード(同名・引数違い)
static int calc(int a) { return a * 2; }
static int calc(int a, int b) { return a * b; }
// 早期リターン(条件を満たしたらすぐ返す)
static String judge(int n) {
if (n < 0) return "負";
if (n == 0) return "ゼロ";
return "正";
}
// 可変長引数(個数が決まっていない)
static int sum(int... nums) {
int total = 0;
for (int n : nums) total += n;
return total;
}
// ⚠ 配列を渡すと呼び出し元も変わる
static void modify(int[] a) {
a[0] = 999;
}
// 基本型は変わらない
static void tryModify(int n) {
n = 999; // ローカルのコピーが変わるだけ
}
public static void main(String[] args) {
System.out.println(add(3, 7)); // 10
greet("山田");
System.out.println(sum(1, 2, 3)); // 6
int[] arr = {1, 2, 3};
modify(arr);
System.out.println(arr[0]); // 999(変わる)
int x = 1;
tryModify(x);
System.out.println(x); // 1(変わらない)
}
}
3基本ドリル(10問)
出力 == 10
static int add(int a, int b) { return a + b; } と書く。
public class Main {
static int add(int a, int b) {
return a + b;
}
public static void main(String[] args) {
System.out.println(add(3, 7));
}
}戻り値の型を先に書くのがJavaの形。int と宣言したら、必ず int を return する必要がある。
A. null B. void C. none D. empty 選択★☆☆無料
解答 == B
「空の」を意味する英単語。
B
void なら return を書かなくてよい。画面に出力するだけのメソッドはこの形になる。
出力 == 山田さん、こんにちは
static void greet(String name) { ... } と書く。return は不要。
public class Main {
static void greet(String name) {
System.out.println(name + "さん、こんにちは");
}
public static void main(String[] args) {
greet("山田");
}
}void は「値を返さない」という意味。出力するだけなら、わざわざ値を返す必要はない。
public class Main {
static int twice(int n) {
____ n * 2;
}
public static void main(String[] args) {
System.out.println(twice(21));
}
}出力 == 42
「返す」を意味する6文字のキーワード。
return
return を書かないとコンパイルエラー。「int を返すと宣言したのに返していない」と指摘される。
A. 変わる B. 変わらない C. エラー D. 0になる 選択★☆☆無料
解答 == B
基本型は値がコピーされて渡される。
B
基本型は値のコピーが渡されるので、メソッド内で変えても呼び出し元には影響しない。配列とは挙動が違う。
出力2行。10 / 15
同じ名前でも引数の数が違えば別のメソッドとして定義できる。
public class Main {
static int calc(int a) {
return a * 2;
}
static int calc(int a, int b) {
return a * b;
}
public static void main(String[] args) {
System.out.println(calc(5));
System.out.println(calc(5, 3));
}
}引数の数や型が違えば同じ名前を使える。System.out.println も、数値・文字列・真偽値を受け取れるオーバーロードの塊。
public class Main {
static int sum(int____ nums) {
int total = 0;
for (int n : nums) {
total += n;
}
return total;
}
public static void main(String[] args) {
System.out.println(sum(1, 2, 3, 4));
}
}出力 == 10
可変長引数を表すピリオド3つ。
...
可変長引数は配列として扱われる。sum(1,2) でも sum(1,2,3,4,5) でも同じメソッドで受けられる。
A. 変わらない B. 変わる C. エラー D. コピーが作られる 選択★★☆広告解放
解答 == B
配列は「場所」が渡される(JV06の参照)。
B
配列は参照が渡るので、中身を変えると呼び出し元にも反映される。便利な反面、意図しない変更に注意が必要。
出力 == 負ゼロ正
条件を満たしたらすぐ return する。else は不要。
public class Main {
static String judge(int n) {
if (n < 0) {
return "負";
}
if (n == 0) {
return "ゼロ";
}
return "正";
}
public static void main(String[] args) {
System.out.print(judge(-5));
System.out.print(judge(0));
System.out.println(judge(10));
}
}return したらそこでメソッドが終わるので、else を書く必要がない。条件が増えてもインデントが深くならない。
出力 == 140800
Math.round の戻り値は long なので、メソッドの戻り値も long にする。
public class Main {
static long withTax(int price) {
return Math.round(price * 1.1);
}
public static void main(String[] args) {
System.out.println(withTax(128000));
}
}計算式に名前を付けると意図が伝わる。Math.round(price * 1.1) より withTax(price) のほうが、何をしているか一目で分かる。
4実践シナリオ(5問)
出力3行
String.format("%,d", n) + "円" を返す。
public class Main {
static String yen(long n) {
return String.format("%,d", n) + "円";
}
public static void main(String[] args) {
System.out.println(yen(128000));
System.out.println(yen(3200));
System.out.println(yen(45000));
}
}同じ整形を3回書かずに済む。書式を変えたくなったら、メソッドの中を1箇所直すだけで全体に反映される。
出力2行。314 / 78.5
average は double を返す。sum メソッドを再利用できる。
public class Main {
static int sum(int[] nums) {
int total = 0;
for (int n : nums) {
total += n;
}
return total;
}
static double average(int[] nums) {
return sum(nums) / (double) nums.length;
}
public static void main(String[] args) {
int[] scores = {80, 75, 91, 68};
System.out.println(sum(scores));
System.out.println(average(scores));
}
}メソッドの中から別のメソッドを呼べる。average が sum を再利用しているので、合計の計算方法を変えても1箇所直すだけで済む。
出力2行。999 / 1
配列は参照が渡るので変わる。int は値のコピーなので変わらない。
public class Main {
static void modifyArray(int[] a) {
a[0] = 999;
}
static void modifyInt(int n) {
n = 999;
}
public static void main(String[] args) {
int[] arr = {1, 2, 3};
modifyArray(arr);
System.out.println(arr[0]);
int x = 1;
modifyInt(x);
System.out.println(x);
}
}同じ「変更する」操作でも結果が違う。配列を渡すメソッドを書くときは、呼び出し元のデータを壊していないかを常に意識する。
出力3行。OK / 未入力です / 長すぎます
trim() してから length() で判定する。21文字は "あ".repeat(21) で作れる。
public class Main {
static String validate(String name) {
String trimmed = name.trim();
if (trimmed.isEmpty()) {
return "未入力です";
}
if (trimmed.length() > 20) {
return "長すぎます";
}
return "OK";
}
public static void main(String[] args) {
System.out.println(validate("ノートPC"));
System.out.println(validate(" "));
System.out.println(validate("あ".repeat(21)));
}
}検証ロジックをメソッドに閉じ込めると、複数の画面から同じ検証を呼べる。ルールが変わっても1箇所直すだけで済む。
出力 == 3件・176,700円
int... prices で受け取る。件数は prices.length。
public class Main {
static String summarize(int... prices) {
int total = 0;
for (int p : prices) {
total += p;
}
return prices.length + "件・" + String.format("%,d", total) + "円";
}
public static void main(String[] args) {
System.out.println(summarize(128000, 3200, 45500));
}
}引数の個数を気にせず呼べる。配列を作って渡す手間が省けるので、呼び出し側のコードが簡潔になる。
5仕上げ課題
作るメソッド(すべて static)
① String yen(long n) … 「128,000円」の形式に整形
② int stockValue(int price, int stock) … 在庫金額を返す
③ String stockLabel(int stock) … 0なら「品切れ」、10未満なら「残りわずか」、それ以外は「在庫あり」
④ int sum(int[] nums) … 配列の合計
⑤ String maxName(String[] names, int[] values) … 値が最大の名前を返す
データ
String[] names = {"ノートPC", "マウス", "モニター", "キーボード"};
int[] prices = {128000, 3200, 45000, 8500};
int[] stocks = {5, 42, 0, 18};
処理:各商品を「1. ノートPC:640,000円(残りわずか)」の形式で出力し、最後に総額と最高額の商品名を表示
期待される出力(6行)
1. ノートPC:640,000円(残りわずか)
2. マウス:134,400円(在庫あり)
3. モニター:0円(品切れ)
4. キーボード:153,000円(在庫あり)
---
在庫総額:927,400円(最高:ノートPC) 総合★★★広告解放
出力6行が完全一致
在庫金額を配列に貯めてから、sum と maxName に渡す。stockLabel は早期リターンで書くと読みやすい。yen は long を受け取るようにすると汎用性が高い。
public class Main {
static String yen(long n) {
return String.format("%,d", n) + "円";
}
static int stockValue(int price, int stock) {
return price * stock;
}
static String stockLabel(int stock) {
if (stock == 0) {
return "品切れ";
}
if (stock < 10) {
return "残りわずか";
}
return "在庫あり";
}
static int sum(int[] nums) {
int total = 0;
for (int n : nums) {
total += n;
}
return total;
}
static String maxName(String[] names, int[] values) {
int maxIndex = 0;
for (int i = 1; i < values.length; i++) {
if (values[i] > values[maxIndex]) {
maxIndex = i;
}
}
return names[maxIndex];
}
public static void main(String[] args) {
String[] names = {"ノートPC", "マウス", "モニター", "キーボード"};
int[] prices = {128000, 3200, 45000, 8500};
int[] stocks = {5, 42, 0, 18};
int[] values = new int[names.length];
for (int i = 0; i < names.length; i++) {
values[i] = stockValue(prices[i], stocks[i]);
System.out.println((i + 1) + ". " + names[i] + ":"
+ yen(values[i]) + "(" + stockLabel(stocks[i]) + ")");
}
System.out.println("---");
System.out.println("在庫総額:" + yen(sum(values))
+ "(最高:" + maxName(names, values) + ")");
}
}JV06と同じ結果を出力しているが、main の中身は劇的に短くなった。集計の計算も金額の整形も判定も、すべてメソッドに移したからだ。main を読めば「何をしているか」が分かり、詳細を知りたければ各メソッドを見ればよい——この構造が、プログラムを理解しやすくする。
メソッド名にも意味がある。stockLabel(stocks[i]) という呼び出しを見れば、中身を知らなくても「在庫のラベルを返すのだろう」と推測できる。もしこれが check(stocks[i]) という名前だったら、何を確認しているのか分からない。良い名前は、コメントの代わりになる。
maxName(names, values) の作りにも注目してほしい。最大値そのものではなく「最大値の添字」を記録している。こうすることで、値の配列と名前の配列の両方から、対応する要素を取り出せる。
ただし、このメソッドには弱点がある。names と values の長さが違ったら破綻するし、順序がずれていても気づけない。「名前と在庫金額は必ずセット」という関係を、引数を2つ渡すことでしか表現できていないのだ。
次章では、いよいよクラスを学ぶ。商品を1つのオブジェクトにまとめれば、この問題は根本から解決する。