戻り値の全体像
戻り値は「メソッドが処理の結果として外へ返す値」です。定義時に「戻り値の型」を決め、return で値を返します。値を返さない場合は型に void を指定します。戻り値は「関数型思考の中心」で、入力(引数)→出力(戻り値)を明確にすると、コードの再利用性・テスト容易性・可読性が大きく向上します。
基本構文と return の動き
最小の書式(値あり/void)
static int add(int a, int b) {
return a + b; // 戻り値の型(int)に一致する値を返す
}
static void greet(String name) {
System.out.println("Hello, " + name);
return; // void では書いても書かなくてもよい(早期終了に使える)
}
Javareturn に到達した瞬間、そのメソッドの実行は終了し、呼び出し元へ制御が戻ります。戻り値ありのメソッドではすべての実行パスで必ず値を返す必要があります(コンパイル時にチェックされます)。
呼び出し側の受け取り
int s = add(3, 8); // 結果を受け取って使う(推奨)
System.out.println(s);
add(1, 2); // 受け取らずに捨てると「何のために呼んだか」が不明確
Java戻り値があるなら、基本的にはそれを使う設計にします。副作用だけを期待して戻り値を捨てる設計は読みづらく、テストしにくいです。
重要ポイントの深掘り:早期 return と単一責務
ガードで早期に返すと本体がまっすぐになる
static String label(int score) {
if (score < 0) return "INVALID";
if (score >= 80) return "A";
if (score >= 70) return "B";
if (score >= 60) return "C";
return "D";
}
Java「対象外を先に返す → 対象だけの直線的な処理」にすると、ネストが浅くなり読みやすくなります。早期 return は「単一責務+明快なフロー」を支える重要テクニックです。
複数の値が必要ならオブジェクトで返す
record Stats(int sum, double avg) {}
static Stats stats(int[] arr) {
int sum = 0;
for (int v : arr) sum += v;
double avg = arr.length == 0 ? 0.0 : sum / (double) arr.length;
return new Stats(sum, avg); // 複数の意味ある値を一つの結果にまとめる
}
Java「配列・タプル風の返し方」では意図が伝わりにくくなります。結果に名前を与えた型で返すと、呼び出し側も読みやすく安全です。
重要ポイントの深掘り:null/既定値/Optional の設計
null を返す設計の注意
static String find(String[] arr, String key) {
for (String s : arr) if (key.equals(s)) return s;
return null; // 見つからない場合
}
Java呼び出し側は必ず null ガードが必要になります。プロジェクト全体で「null を返すか返さないか」を方針として統一しましょう。
既定値で返す(呼び出し側に優しい設計)
static String findOrDefault(String[] arr, String key, String def) {
for (String s : arr) if (key.equals(s)) return s;
return def; // null を返さず安全な既定値へ
}
Java「見つからないときはこうする」を API で表現します。分岐が減り、誤用が減ります。
Optional を返す(API 設計向け)
import java.util.Optional;
static Optional<String> findOpt(String[] arr, String key) {
for (String s : arr) if (key.equals(s)) return Optional.of(s);
return Optional.empty();
}
// 呼び出し側
String v = findOpt(arr, "A").orElse("unknown");
JavaOptional は「結果がある/ない」を型で表現し、null を避けるのに有効です。ライブラリ的なコードでは特に有用です。
重要ポイントの深掘り:不変・副作用・メソッドチェーン
純粋な戻り値はチェーンしやすい
String out = "java"
.trim() // 新しい String を返す(元は変わらない)
.toUpperCase()
.replace("A", "@");
Java戻り値が不変(イミュータブル)だと、連鎖で読みやすく書けます。可変オブジェクト(StringBuilder など)は「同じインスタンスを変更」するため、戻り値の意味が変わります。
StringBuilder sb = new StringBuilder("Hi");
sb.append("!").append("?"); // 戻り値は同じ sb(副作用)
Java「戻り値が新値か、同じインスタンスか」を理解して使い分けましょう。
例外と戻り値の関係(返すか、投げるか)
異常系は例外で表現するのが基本
static int divide(int a, int b) {
if (b == 0) throw new IllegalArgumentException("b must not be 0");
return a / b;
}
Java「正常系の戻り値」「異常系は例外」で役割を分けると、呼び出し側の分岐が明確になります。「エラーコードを戻り値で返す」設計は分岐が増え、見落としが起きやすくなります。
実用例で身につける
例 1: 合否ラベル(早期 return)
public class PassFail {
static String label(int score) {
if (score < 0) return "INVALID";
return (score >= 60) ? "PASS" : "FAIL";
}
public static void main(String[] args) {
System.out.println(label(75)); // PASS
}
}
Java例 2: 集計結果をオブジェクトで返す
public class StatsDemo {
record Stats(int sum, double avg) {}
static Stats stats(int[] arr) {
int sum = 0;
for (int v : arr) sum += v;
double avg = arr.length == 0 ? 0.0 : sum / (double) arr.length;
return new Stats(sum, avg);
}
public static void main(String[] args) {
Stats s = stats(new int[]{3,8,2});
System.out.printf("sum=%d avg=%.2f%n", s.sum(), s.avg());
}
}
Java例 3: Optional で結果の有無を表現
import java.util.Optional;
public class OptionalFind {
static Optional<String> find(String[] arr, String key) {
for (String s : arr) if (key.equals(s)) return Optional.of(s);
return Optional.empty();
}
public static void main(String[] args) {
String[] a = {"A","B"};
String v = find(a, "C").orElse("unknown");
System.out.println(v); // unknown
}
}
Java設計の指針(重要部分のまとめ)
- 戻り値は「結果」。早期 return で本体を直線化し、全パスで必ず返す。
- 複数の値は意味のある型(record/クラス)でまとめて返す。配列・リストだけで返して意図を曖昧にしない。
- null を返すかどうかを方針として決める。代替として既定値や Optional を活用し、呼び出し側の負担を減らす。
- 戻り値が不変ならチェーンしやすい。可変オブジェクトは副作用を理解して使い分ける。
- 異常は例外で表現し、正常系の戻り値と役割を分離する。戻り値を捨てる呼び方は避ける。
