概要
Javaのメソッド内で引数のインスタンスに変更を加える場合に
"メソッドの実行によって呼び出し元のインスタンスにも変更は加わるが、あえて明示的に戻り値として返却するべきなのか?"の疑問に対して、一つ納得できる答えを知ることができたため、その備忘録。
前提
Javaのメソッド処理には、「値渡し」と「参照の値渡し」が存在する。
値渡し:呼び出し先のメソッド処理により、呼び出し元の変数の状態が変化しない。
参照の値渡し:呼び出し先のメソッド処理により、呼び出し元の変数の状態が変化する。
値渡しになるか参照の値渡しになるかはメソッドの引数により異なり、
プリミティブ型(boolean、byte、char、short、int、float、long、double)の場合は値渡し、
それ以外の場合では参照の値渡しとなる。
今回は参照の値渡しの場合の、戻り値の必要性についてのお話。
例
private String name;
private int age;
// Getter,Setterは省略
①戻り値を記載する場合
public static void main(String args[]) {
Human human = new Human();
human.setName("田中");
human.setAge(30);
// メソッド返却値を新たなHumanインスタンス「youngerHuman」として定義
Human youngerHuman = rejuvenate5Years(human);
System.out.println("名前は" + youngerHuman.getName() + "です。");
System.out.println("年齢は" + youngerHuman.getAge() + "歳です。");
}
// 5歳若返りメソッド
// 引数のHumanインスタンスを編集し、返す
private static Human rejuvenate5Years(Human human) {
human.setAge(human.getAge() - 5);
return human;
}
rejuvenate5Yearsメソッドで、引数のインスタンスに対しageを5歳若く設定し直して返却している。
②戻り値を記載しない場合
public static void main(String args[]) {
Human human = new Human();
human.setName("田中");
human.setAge(30);
// メソッド呼び出しのみ
rejuvenate5Years(human);
System.out.println("名前は" + human.getName() + "です。");
System.out.println("年齢は" + human.getAge() + "歳です。");
}
// 5歳若返りメソッド
// 戻り値はvoid
private static void rejuvenate5Years(Human human) {
human.setAge(human.getAge() - 5);
}
出力結果は同じ。明示的にインスタンスの返却をしていない。
結論
②戻り値を記載しない
引数で取得したインスタンスを変更させている場合、戻り値はvoidとする。
理由:戻り値がない⇒引数で渡したインスタンスの中身を変更しているんだろう、と読み手に推測させることができるから。
returnもせず、引数のインスタンスも変更していない場合、そのメソッドは何もしない無意味のメソッドとなってしまう。
そんなメソッドはありえないため、「戻り値がvoidだから引数のインスタンスに何かしら変更を加えるメソッドだ」と判断ができる。
逆に、
戻り値を作る場合には、引数で渡したインスタンスには何も変更を加えず、新しくインスタンスを作成したものを戻り値とすべき。
③新しくインスタンスを作成したものを戻り値とする
// 引数のhumanは変更せず、新たなインスタンスを生成する。
private static Human rejuvenate5Years(Human human) {
Human youngerHuman = new Human();
youngerHuman.setName(human.getName());
youngerHuman.setAge(human.getAge() - 5);
return youngerHuman;
}
結論
「引数のインスタンスも変更するし、戻り値も返す」だと、メソッドの動作が直感的に分かりにくくなってしまう。
そのため、
・引数のインスタンスを直接変更する場合、戻り値はvoidとする。
・引数をもとに新たにインスタンスを作成し処理する場合のみ、そのインスタンスを戻り値とする。