
Javaのreturnとは?メソッドから戻る・戻り値を戻すreturnの使い方と活用方法
Javaでのreturnは、メソッドの実行を終了させて呼び出し元に処理を戻す時と、呼び出し元に戻り値を戻す時に使うものです。
と、このようにreturnは単純なものではありますが、時にプログラマを惑わせます。特に、try-catch-finallyと組み合わさった時は、人によっては直感と反する動きになります。
そして、メソッドのどこでどうやってreturnをするか。これはプログラムの分かりやすさにも大きく影響する、なかなか侮れないものなのです。
この記事では、returnの使い方を基本からお伝えします。そして、分かりやすいプログラムを作るためのreturnもお伝えしますので、ぜひこの記事で色々なコツを学んで行ってください。
※この記事のサンプルは、Java 11の環境で動作確認しています
1.【Java】returnとはどういうものか
1-1.returnはメソッドをすぐ終了させ、戻り値を戻すもの
returnを実行する(「returnする」ともよく言います)と、メソッドの実行をその場ですぐに終了させて、プログラムの実行箇所を呼び出し元に戻します。さらに、メソッドの処理結果となる値を呼び出し元に戻す役割も持っています。
ちなみに、プログラムでreturnという単語が使われるのは、プログラムの制御を呼び出し元に「戻す」、あるいは処理結果を呼び出し元に「戻す」からです。
1-1-1.メソッドの実行をその場ですぐ終了させる
returnすると、returnよりも後ろに書いてある処理は実行されません。さらに、returnより後ろの処理がいかなる状況でも動かないことが明確な場合は、コンパイルエラーになってしまうことがあります。
class ReturnSample {
	static void returnInMiddle(boolean b) {
		System.out.println("returnする前"); // この処理は当然実行されて…
		// このif文の中でreturnしてしまうと、そこから後ろは動かない!!
		if (b) {
			System.out.println("returnします");
			return;
		}
		System.out.println("returnした後"); // この処理は実行すらされない
	}
	public static void main(String[] args) {
		System.out.println("メソッドを呼ぶ前");
		returnInMiddle(true);
		System.out.println("メソッドを呼んだ後");
	}
}実行結果
メソッドを呼ぶ前 returnする前 returnします ←この後に"returnした後"が表示されていません メソッドを呼んだ後
1-1-2.メソッドの処理結果を戻す
returnすると、メソッドから呼び出し元に値を戻せます。メソッドの呼び出し元では、戻り値をメソッドの処理結果として使うのが普通です。どういう値が戻せるかは、メソッドの宣言のされ方によります。詳細は次の章でお伝えします。
class ReturnSample {
	static int multiply(int num) {
		int ret = num * 1000000; // ②メソッドの中で引数の数字を100万倍して、
		return ret; // ③その値をreturnで呼び出し元に戻すと、
	}
	public static void main(String[] args) {
		int num = multiply(123); // ①123を引数にメソッドを呼び出して、
		System.out.println(num); // ④123000000が得られている。メソッドで計算した結果が戻ってきている!!
	}
}1-2.returnはメソッドの中ならいつでもできる
returnできるのはメソッドの中に限られています。細かく言えば、メソッドの中か、メソッドの一種ともみなせるコンストラクタの中か、メソッドを実装することと同じ意味であるラムダ式の中にしか書けません(※Java 11時点では)。
import java.util.function.Consumer;
class ReturnSample {
	// コンストラクタからのreturn
	ReturnSample() {
		return;
	}
	// インスタンスメソッドからのreturn
	void instanceMethod() {
		return;
	}
	// staticメソッドからのreturn
	static void staticMethod() {
		return;
	}
	// ラムダ式でのreturn
	void lambdaExpression() {
		Consumer<String> c = s -> {
			return;
		};
	}
}returnはいつでもできます。ですから、「もうこのメソッドの処理は終わりでいいや」となったら、その時点ですぐさまreturnできます。ですからfor文/while文のようなループ構文の中、if文/switch文のような条件判定の中、それ以外の部分でもreturnできます。
for (int i = 0; i < 10; i++) {
	if (i > 5) {
		return; // for文の中でもreturnできる
	}
}
int i = 0;
while (i < 10) {
	if (i > 5) {
		return; // while文の中でもreturnできる
	}
}
int j = 0;
switch(j) {
case 0:
	break;
case 1:
	return; // switch文の中でもreturnできる
}
int k = 0;
if (k > 10) {
	return; // if文の中でもreturnできる
}2.【Java】returnと戻り値
returnは、一つのメソッドの中では戻り値がある・ないの必ずどちらか一方です。どちらになるかはメソッドの宣言のされ方、特に戻り値の有無で決まります。
2-1.戻り値がvoidでないなら戻り値が必須
メソッドの宣言で戻り値がvoidではないなら、returnには戻り値となる値、あるいは戻り値とするインスタンスを指す変数を「必ず」指定しなければなりません。つまり、以下の書き方になります。
return 戻り値;
それに、メソッドのどこかで、戻り値があるreturnを「必ず」しなければなりません。そうしないとコンパイルエラーです。メソッドの戻り値が分からなくなってしまうからですね。メソッドの戻り値は、メソッドが呼び出したなら必ずその型の値が戻るという「約束」です。それは絶対に守る必要があるのです。
// このメソッドの戻り値はint、だから必ずintをreturnしなければならない
int method() {
	// メソッドの途中でのreturnは自由に行える
	if (何かの条件) {
		return 0;
	}
	// でも、ここに何も書いていないなら、コンパイルエラー!!
	// ifの条件が満たされなかった場合は何が戻るのか分からない
}なお、他のプログラミング言語では、プログラマがreturnを書かなくても、メソッドや関数の中で「最後に評価された式の結果」が戻り値になるものがあります。ですが、Javaでは必ず明示的にreturnをしなければなりません。これはJavaでは絶対に守らなければならないルールです。
2-2.returnの戻り値は互換性がある値や型であればよい
returnの戻り値は、プリミティブ型ならその値か変数、参照型(≒クラス、配列)ならその型と見なせるインスタンスを指す変数かnullです。プリミティブ型は分かりやすいのですが、参照型は少し注意が必要です。ここに、オブジェクト指向プログラミング言語であるJavaの特徴が現れます。
例えば、以下のメソッドでreturnできるのは、NumberそのものかNumberのサブクラスのインスタンスです。具体的にはInteger/Long/Doubleなどです。なぜかと言うと、IntegerやDoubleはNumberとの間で「IS-A関係」と言うものが成立し、IntegerやDoubleはNumberだとみなせるからです(Integer is a Number)。
【参考】is-a(Wikipedia)
// 戻り値の型がクラスのNumberなので…
Number getNumber() {
	// NumberのサブクラスのIntegerもreturnできるし、
	if (何かの条件) {
		return Integer.valueOf(1);
	}
	// NumberのサブクラスのLongもreturnできるし、
	if (何かの条件) {
		return Long.valueOf(2);
	}
	// NumberのサブクラスのDoubleもreturnできるし、
	if (何かの条件) {
		return Double.valueOf(3.14);
	}
	// nullでもreturnできる
	return null;
}この約束事が守られていないクラスのインスタンスは戻り値にはできません。ですので、以下のメソッドはコンパイルエラーになるのです。
// 戻り値の型がクラスのIntegerなので…
Integer getInteger() {
	// Integerはもちろんreturnできるけれど、
	if (何かの条件) {
		return Integer.valueOf(1);
	}
	// NumberのサブクラスのLongはIntegerではないのでreturnできなくて、
	if (何かの条件) {
		return Long.valueOf(2);
	}
	// NumberのサブクラスのDoubleもIntegerではないのでreturnできない
	if (何かの条件) {
		return Double.valueOf(3.14);
	}
	// 参照型の戻り値ならnullはreturnできる
	return null;
}2-3.戻り値がvoidなら戻り値を返せない
メソッドの戻り値がvoidなら、returnには戻り値を指定できません。戻り値を指定すると、コンパイルエラーになります。つまり、以下の書き方だけになります。なお、コンストラクタでreturnする場合も、コンストラクタには戻り値はない(書かないですよね?)扱いがされるので、こちらの書き方になります。
return;
メソッドの中でreturnをすることは、メソッドの戻り値がvoidなら必須ではありません。メソッドの終わりまで行きつけば、そこでメソッドの実行は自動的に終わって、呼び出し元に処理が自動的に戻ります。
// このメソッドの戻り値はない(void)、だからreturnは必須ではない
void method() {
	// 何かの条件を満たすなら、途中でreturnしてもいい
	if (何かの条件) {
		return;
	}
	// ここでreturnしなくても、コンパイルエラーにはならない
}ですので、戻り値がないメソッドなら、returnすべきところにだけ書くのが普通です。もちろん、returnを書いてもコンパイルエラーにはなりません。でも、他のプログラマからは「余計なreturnだなぁ、returnのことをわかってるのかなぁ」と思われてしまうかもしれませんよ。
3.【発展】returnのいろいろ
3-1.returnでは三項演算子を上手に使おう
三項演算子は、使う人は積極的に使い、使わない人は全然使わないという、プログラマの間でも好き嫌いが大変激しい演算子です。でも、三項演算子はreturnと大変相性がいいものでもあります。
三項演算子は文ではなく式なので、returnのパラメータとして記述できます。すると、それがreturnのための記述であることが明確になります。さらに構文上でelse扱いの記述が必須なので、if文でうっかりelseを書き忘れるというような凡ミスを防げもします。
int i = 100;
// if文を使った場合
if (i > 100) {
	return 1;
} else {
	return 0;
}
// 三項演算子を使った場合
return i > 100 ? 1 : 0;しかも、この例ではif文で5行使う処理を三項演算子では1行で書けていて、やっていることは(慣れてしまえば)一目瞭然です。if全体を視線を動かして調べるよりも、ぱっと見るだけでreturnの全体・意図が分かるのが良いと感じます。
もちろん、三項演算子は複雑な条件は苦手なので、if文とは適材適所です。でも、分かりやすくて読みやすいプログラムになるかもしれませんので、食わず嫌いをするよりも、簡単なところからだけでも使ってみてはいかがでしょうか。
3-2.try-catch-finallyとreturnにはご注意を!!
さて、以下のようにtry-catch-finallyのそれぞれでreturnを書いた場合、メソッドtryCatchFinallyの戻り値はどうなるでしょうか。tryの中で例外がthrowされない場合、throwされる場合で分けて考えてみましょう。
class ReturnSample {
	static int tryCatchFinally(boolean throwException) {
		String str = throwException ? null : "";
		System.out.println(0);
		try {
			str.toString(); // Exceptionをthrowするかもしれない何かの処理
			return print(1); // 1をreturn
		} catch (Exception e) {
			return print(2); // 2をreturn
		} finally {
			return print(3); // 3をreturn
		}
	}
	static int print(int i) {
		System.out.println(i);
		return i;
	}
	public static void main(String[] args) {
		System.out.println("return:" + tryCatchFinally(false)); // → 例外がthrowされない場合
		System.out.println("return:" + tryCatchFinally(true)); // → 例外がthrowされる場合
	}
}答え合わせです。例外がthrowされない場合は3、される場合も3です。合っていましたか? なぜかこうなるかと言うと、一番最後に実行されるfinallyでreturnをしているからです。
実行結果
0 1 3 return:3 0 2 3 return:3
イメージ的には、try-catch-finallyの中でreturnすると、returnする値がJava上のどこかに予約され、returnが動くと上書きされる…という感じでしょうか。ですので、try-catch-finallyの中で一番最後に実行されるfinallyでreturnした値が、最終的なメソッドの戻り値になるのです。
3-2-1.例外がthrowされない場合
この場合は、try→finallyの順番で動きます。例外がthrowされていませんので、catchは動きません。finallyはtryの結果が何であれ、tryの後に必ず実行されます。もう少し細かく言うなら、tryのreturnが動いた後に実行されます。
tryが終わった時点で、returnする値としては1であるとJavaは一旦覚えます。ですが、finallyでもう一度returnが呼ばれました。ですので、returnする戻り値がfinallyで指定されている3に入れ替わります。
3-2-2.例外がthrowされる場合
この場合は、try→catch→finallyの順番で動きます。例外が途中でthrowされているのでtryのreturnまでは到達しませんが、catchのreturnは動きます。finallyはcatchの結果がどうであれ、catchの後に必ず実行されます。もう少し細かく言うなら、catchのreturnが動いた後に実行されます。
catchが終わった時点で、returnする値としては2であるとJavaは一旦覚えます。ですが、finallyでもう一度returnが呼ばれました。ですので、returnする戻り値がfinallyで指定されている3に入れ替わります。
3-2-3.finallyでreturnするならtry/catchに要注意!!
ということで、finallyでreturnするとtryやcatchでreturnしても、メソッドの戻り値としては無視されてしまうことがお分かりいただけたかと思います。ですので、finallyでreturnする時は、意図に反した戻り値にならないように、tryやcatchでreturnしていないかをよく調べましょう。
もしfinallyでだけでreturnをしたいなら、戻り値を入れる変数をtryの外で宣言して使うなどしてもいいでしょう。
int tryCatchFinally() {
	int ret = 0; // 戻り値の変数を宣言(デフォルトは0)
	try {
		// Exceptionをthrowするかもしれない何かの処理
		ret = 1;
	} catch (Exception e) {
		ret = 2;
	} finally {
		return ret;
	}
}3-3.returnで複数の値を戻す方法あれこれ
Javaのreturnで戻せるモノは一つだけです。他のプログラミング言語では複数の値を戻す構文、いわゆるタプル(tuple)と呼ばれるものなどがありますが、残念ながらJava 11の時点では一つだけです。
それでも、Javaでも複数の値を戻す方法がないではありません。ここではその方法をいくつか紹介します。
3-3-1.配列/List/Mapを使う
最も単純な方法は、配列やListを使うことです。この場合は、インデックスごとにどんな値が入るのかを、仕様やJavadocで明確にしておく必要があります。ただ、インデックスを間違えてしまうと必要な値を得られないので、呼び出し元では十分に気を付ける必要があります。
さらに柔軟にやりたいならMapを使います。キーとして文字列を使うと分かりやすいです。キーとする文字列はあらかじめ決めておき、クラスを使う人に教えておきます。これもキーを間違えてしまうと値が取得できないので、気を付けましょう。
この方法を使う場合、戻したい値の型が一つなら、まだ大きな問題はありません。しかし、違う型を使いたい場合は最悪Objectにせざるを得ず、呼び出し元でキャストが必要になります。キャストが必要だと、プログラムもしづらいものになりますし、深刻なバグの原因にもなりえます。
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class MultipleReturnSample {
	static int[] multipleReturn1() {
		return new int[] { 1234, 5678 };
	}
	static List<Integer> multipleReturn2() {
		return Arrays.asList(1234, 5678);
	}
	static Map<String, Integer> multipleReturn3() {
		Map<String, Integer> ret = new HashMap<>();
		ret.put("returnValue1", 1234);
		ret.put("returnValue2", 5678);
		return ret;
	}
	static Object[] multipleReturn4() {
		// IntegerとStringを配列で一緒に戻したいなら、Object[]にせざるを得ない
		return new Object[] { Integer.valueOf(1234), "5678" };
	}
	public static void main(String[] args) {
		int[] ret1 = multipleReturn1();
		System.out.println(ret1[0]); // → 1234
		List<Integer> ret2 = multipleReturn2();
		System.out.println(ret2.get(0)); // → 1234
		Map<String, Integer> ret3 = multipleReturn3();
		System.out.println(ret3.get("returnValue1")); // → 1234
		Object[] ret4 = multipleReturn4();
		Integer i = (Integer) ret4[0]; // 配列の型はObjectなので、インデックス0のIntegerにはキャストが必要
		System.out.println(i); // → 1234
	}
}3-3-2.戻り値専用のクラスを使う
戻り値を表現するためのクラスを作って使う方法です。これなら戻り値の型を必要なものだけにできますし、値を取得する際にインデックスやキー文字列を意識しなくてもいいので、お勧めです。戻したい値はコンストラクタで設定し、クラスは値を取得するgetterのみを持つようにするといいでしょう。
ただし、複数の値を戻したいメソッドが多くなると、これだと専用のクラスをたくさん作ることになり、ちょっと大変になってきます。それに、値として扱うクラスが少しだけ違うものがプログラム全体でたくさん作られてしまうことにもなりかねません。そうなると、プログラムはカオスまっしぐらです。
class MultipleReturnValue {
	private final String value1;
	private final Integer value2;
	MultipleReturnValue(String value1, Integer value2) {
		this.value1 = value1;
		this.value2 = value2;
	}
	String getValue1() {
		return value1;
	}
	Integer getValue2() {
		return value2;
	}
}class MultipleReturnSample {
	static MultipleReturnValue multipleReturn() {
		return new MultipleReturnValue("1234", 5678);
	}
	public static void main(String[] args) {
		MultipleReturnValue ret = multipleReturn();
		System.out.println(ret.getValue1()); // → "1234"
		System.out.println(ret.getValue2()); // → 5678
	}
}3-3-3.複数の戻り値を柔軟に管理できるクラスを作る
もっと柔軟なやり方にしたいなら、型引数を活用して、複数の戻り値を汎用的に扱うことに特化したクラスを用意するといいでしょう。以下の例では、二つの値がペアになるので、Pairというクラスにしています。値を増やすなら、数に応じた名前にしましょう(三つならTripleとかです)。
class Pair<V1, V2> {
	private final V1 value1;
	private final V2 value2;
	Pair(V1 value1, V2 value2) {
		this.value1 = value1;
		this.value2 = value2;
	}
	V1 getValue1() {
		return value1;
	}
	V2 getValue2() {
		return value2;
	}
}class MultipleReturnSample {
	// このメソッドでは戻り値はStringとCharacterで、
	static Pair<String, Character> multipleReturn1() {
		return new Pair<>("1234", 'あ');
	}
	// このメソッドでは戻り値はIntegerとDoubleとなる
	static Pair<Integer, Double> multipleReturn2() {
		return new Pair<>(1234, 5678.9);
	}
	public static void main(String[] args) {
		// 戻り値のクラス自体は同じPairなのに、1番目、2番目の型を違うものにできている!!
		Pair<String, Character> ret1 = multipleReturn1();
		System.out.println(ret1.getValue1()); // → "1234"
		System.out.println(ret1.getValue2()); // → 'あ'
		Pair<Integer, Double> ret2 = multipleReturn2();
		System.out.println(ret2.getValue1()); // → 1234
		System.out.println(ret2.getValue2()); // → 5678.9
	}
}なお、このようなクラスと似たものは、標準APIの中に一応あります(javafx.util.Pair、java.util.AbstractMap.SimpleEntryなど)。でもクラスのパッケージがJavaFXだったりするので、なかなか気付きづらいです。それに、メソッド名がキー(Key)と値(Value)なので、ここで表現したいこととは方向性が違います。
また、こういうクラスを数多く提供する外部ライブラリもありますので、それらを使ってもいいでしょう。例えば、Apache Commons LangのPairやTriple、javatuples(https://www.javatuples.org/)のPair、Tripletなどです。
3-4.thisをreturnする
returnでは自分自身をreturnできます。つまり、thisをreturnできるのです。一見何に使うか分かりませんが、メソッドチェーンと呼ばれるものを使う場合にそうしたりします。
class ReturnSample {
	ReturnSample method(String str) {
		System.out.println(str); // 何かの処理を行って…
		return this; // 自分自身をreturnする!!
	}
	public static void main(String[] args) {
		// method()は戻り値としてインスタンス自身が戻る
		// だから、このように「繋げて」メソッドを呼べる
		new ReturnSample().method("A").method("B").method("C").method("D").method("E");
		// ↑は、これと同じことをしている
		ReturnSample sample = new ReturnSample();
		sample.method("A");
		sample.method("B");
		sample.method("C");
		sample.method("D");
		sample.method("E");
	}
}メソッドチェーンは、例えばStringBuilderでappendをする時の常とう手段です。こうすることで、同じモノに対して連続して何かをしているのだということが、プログラム上でも明確になります。また、単純にプログラムの行数を少なくしたり、見た目をスッキリさせる効果もあります。
これをさらに推し進めると「流れるようなインターフェイス(fluent interface)」と呼ばれるプログラミング手法に、いずれたどり着きます。ここでは詳細は述べませんが、興味があれば調べてみてもいいでしょう。参考になる知識が得られるでしょうし、既存のフレームワークでも使っているものは多いです。
3-5.nullかもしれないならOptionalをreturnする
Optionalというクラスをreturnすると「戻り値がnullかもしれないから気を付けてね」と教えてあげられます。この章で、複数の値を戻す時はPairのようなクラスを使うとよいとお伝えしましたが、同じような考え方です。
NullPointerExceptionの主な発生理由は、メソッドの呼び出し元でのnullチェックのし忘れだったりします。メソッドの戻り値が参照型ならnullをreturnでき、これはごく普通のことですが、メソッドの呼び出し元でnullのチェックをしてくれるとは限りません。
でも、Javaではメソッドの呼び出し元へnullチェックを強制することが、文法上で出来ません。ですから、Optionalを使って本当の戻り値を包み込んでreturnして、本当の戻り値をOptionalから取得する時にnullチェックをしてもらうのです。
import java.util.Optional;
class ReturnSample {
	// nullかもしれない値を戻すメソッドの戻り値をOptionalにして、Optionalをreturnする
	static Optional<String> getNullable() {
		String ret = null;
		// 戻り値がnullかそうでないかがメソッド内部の処理で決まって…
		return Optional.ofNullable(ret); // 結果をOptionalに「包んで」returnする
	}
	public static void main(String[] args) {
		// Optionalでメソッドから値を受け取って…
		Optional<String> ret = getNullable();
		// 値がnullでないならprintする。if文でのnullチェックが不要!!
		ret.ifPresent(System.out::println);
		// 値がnullの場合のデフォルト値を指定できる。ここでもif文でのnullチェックが不要!!
		String str = ret.orElseGet(() -> "nullみたいですよ?");
		System.out.println(str);
	}
}詳細は以下の記事を参照してください。
関連記事4.【発展】returnのスタイル
returnの「スタイル」はいろいろあります。大きな分け方では、①メソッドの途中で即座にreturnする(早期return)、②メソッドの最後や決まった場所だけでreturnする…の二つです。実際には①と②の折衷案になるのですが、それぞれメリット・デメリットがありますので、簡単に紹介します。
4-1.【お勧め】条件次第で即returnする「早期return」
4-1-1.早期returnの特徴
早期return(early returns)は、メソッドを実行する必要性や理由がなくなったなら、その時点ですぐreturnするスタイルです。見た目上の特徴は、if文でのelseが少なく、各if文の条件が比較的シンプルです。代表的な適用先は引数チェックですが、それに限りません。そして、私のお勧めスタイルはこちらです。
class ReturnSample {
	int earlyReturn() {
		if (何かの条件1) {
			return 1; // 条件1を満たせば即returnする
		}
		if (何かの条件2) {
			return 2; // 条件2を満たせば即returnする
		}
		if (何かの条件3) {
			return 3; // 条件3を満たせば即returnする
		}
		return 0; // すべての条件を満たさなかった場合
	}
}このスタイルの利点は、if文の構造や判定条件が簡単になること、メソッド内のインデントがかなり減ることです。つまり、メソッドの構造が簡潔になるのです。でも、よくあるプログラムの仕様書にある条件とは、処理結果は同じでも違った形になるので、ソースレビュー時に修正指示が出るかもしれませんね。
この例だと、条件2に処理が来るのは、条件1を満たさない場合だけです。ですので、条件1の後ろはif-elseのelseの部分だとも言えます。同じように、条件3に処理が来るのは、条件1と条件2の両方を満たさない場合です。途中にelseはありませんが、returnにより実質的に同じことを表現できています。
ですから、早期returnを積極的に使うスタイルは、目には見えない大きなif-else if~を、メソッド全体で表現するスタイルである…とも言えるでしょう。
4-1-2.早期returnはメソッドを読むのに必要なことを少なくする
早期returnのうれしい点は、returnした後ろではreturn済みの条件を考えなくてもいいことです。プログラムを作ったり読んだりする作業は、仮定や条件が少なくなればなるほど、やりやすくなるものです。早期returnをすれば、プログラマが一度に覚えたり考えなければならないことがグンと減るのです。
ちなみに、ループ部分でのbreakやcontinueにも早期returnと同じ考え方ができます。早期breakや早期continueという言葉は聞いたことがありませんが、早期returnと同じように早めにbreakなりcontinueをすれば、ループ部分がかなり読みやすくなるのです。
4-2.メソッドの最後や決まった場所だけでreturnする
もう一つのreturnのスタイルは、returnをする箇所はメソッドの最後やメソッドの途中の決まった箇所だけとするものです。
class ReturnSample {
	int onlyOnceReturn() {
		int ret = 0; // 戻り値の変数をデフォルト値で初期化
		if (何かの条件1) {
			ret = 1;
		} else if(何かの条件2) {
			ret = 2;
		} else if (何かの条件3) {
			ret = 3;
		}
		return ret; // returnはメソッドの最後だけでやる
	}
}このスタイルだと、どこから入ってどこから出る、という流れが分かりやすくはなります。それに、よくあるプログラムの設計書に書いてあるような、処理全体の流れやいろいろな条件を素直に作ると、こういう書き方になるのが普通でしょう。
ですが、このスタイルは判定条件が複雑になりがちで、そうなるとメソッド全体のインデントが深くなり、見通しが悪くなることが多いです。一つのifに対応するelse-ifが、数十行~数百行も後ろにある…などということもよく起こります。それに全ての条件を網羅した、ものすごく複雑なif文にもなりがちです。
そういうメソッドを理解するのはかなり大変です。なぜかと言うと、人間が一度に覚えていられることはせいぜい数個だからです。極端な話、メソッドの最後でだけでreturnをするなら、return直前ではメソッドの中で宣言した全ての変数が見えるのですが、それぞれどういう状態か理解するのはすごく大変です。
4-3.できる範囲で早期returnをしよう!!
実際のプログラミングの現場では、結局はこの二つのスタイルが混ざるのが普通です。早期returnをするなら仕様書などにあるロジックを解釈して、同じ動きをするように再構成しなければなりませんが、そこでミスをしないとも限りません。早期returnを意識して仕様を書いてくれる人は少ないでしょうしね。
ですが、テスト駆動開発などの「このメソッドはこう動くべき」ということを事前に明確にするプログラミングスタイルならば、失敗を恐れることなく、積極的に早期returnへチャレンジしてもらいたいです。その効果を実体験できたならチームの中にも広めて、読みやすいプログラムを作るチームを作りましょう。
5.まとめ
この記事ではJavaのreturnについてお伝えしてきました。returnでメソッドを終了させる、そして戻り値を戻す。returnはプログラミングをする上での基本的なことではありますが、returnの正しい理解はプログラムには絶対に欠かせないものです。
そして、プログラムの中でreturnをどう実行するかは、プログラマにすべて任せられています。早期returnなどの工夫をすると、より分かりやすいプログラムに一歩近づけるでしょう。
あなたや周囲のプログラマが作ったプログラムは、分かりやすく読みやすいものでしょうか? もし、少しでも読みづらいなぁと感じているなら、returnの仕方に注目してみると、もしかすれば解決への糸口がつかめるかもしれませんよ。





コメント