質問するログイン新規登録

Q&A

解決済

10回答

5059閲覧

if文のリファクタリング

k499778

総合スコア599

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2017/05/17 13:26

0

0

現在Javaでif文のコードを書いています。

if文のコードの良い書き方(リファクタリング)について教えて頂きたいです。

次のコードはどのように書くのがベターでしょうか?

Integer型の変数num1,num2があり、どちらもnullでない場合、差を計算し、その結果を返すメソッドです。

私は以下のように書きましたが、もっといい書き方があれば教えて頂きたいです。
if文のreturnは早く返した方がいいとリファクタリングの本で見た気がするのでその観点で実装しています。

public int getNum3(Integer num1,Integer num2){
int num3 =0;
if(num1==null&&num2==null){
return num3;
}
num3 = num2-num1;
return num3 ;
}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

guest

回答10

0

いろんな意見があり面白いですね。

10件目くらいの意見としては、リファクタリングがコードを易くする作業だとするならメソッドの定義に違和感をおぼえます。

引き算をするメソッドがgetNum3と言う点のツッコミをほっといても、引き算をするメソッドでNullを許容している点はおかしいと思います。さらに、その時の戻り値が0これって以下のケースですべて戻り値が0になると言うことです。

getNum3(1000, 1000) == 0;
getNum3(0, 0) == 0;
getNum3(Null, 84) == 0;
getNum3(-553, Null) == 0;

どういう要件か解りませんがこれが正しい動作である気がしません。
そのまま例外を投げるか、Null伝播が適当だと思われます。

getNum3(1000, 1000) == 0;
getNum3(0, 0) == 0;
getNum3(Null, 84) == Null;
getNum3(-553, Null) == Null;

投稿2017/05/18 04:55

iwamoto_takaaki

総合スコア2884

swordone

2017/05/18 05:03

そういう意味では私の方法ではOptionalで返したい。
iwamoto_takaaki

2017/05/18 05:13

Optionalで返すもの優れた選択肢だと思います。それも入れておくべきでした。(例外/Optional/Nullのどれを選ぶのかは、場合によって変わってくるとおもいます。) 異常な入力に対して、正常な値を返すのは良くないという点は同意してもらえるとおもいます。
k499778

2017/05/18 08:57

回答ありがとうございます。 それでいうと要件としては以下になります。 1.web apiを使ってデータが送られてくる。 2.データがないときは配列に項目がないためNULLとなる 3.num2が全体の数値、それからnum1を引いたものがnum3 そのため実際にはこのように書きました。 public int getNum3(Integer num1, Integer num2) { if (num2 == null) return 0; if (num1 == null) return num2; return num2 - num1; }
iwamoto_takaaki

2017/05/18 10:31 編集

なるほど、APIの仕様だろうけど、入力はNullになるところが少し違和感があります。空の配列が帰ってきていたら入力は0になるのに・・・(XMLやJSONなどだったら仕方がないかも・・・) 逆に意味論から言うと、こんなコードが意図がつかみやすいと思います。 public int culcRemainderCount(int index, int all){ if(index == null) index = 0; if(all == null) all = 0; return all - index; } メソッド名、変数名などは適当ですが、変数がnullの時は0とみなしているという意図がはっきりしているのが判るとおもいます。 ガード節を使う方が効率的になりますが、実行速度を上げるのはリファクタリングの目的にはならないので、読みやすさを優先させるのがよいと思います。
k499778

2017/05/18 12:04

回答ありがとうございます。 大変わかりやすく自分にはない発想なのでまた武器が1つ増えました。 そうですね。こちらのコードを参考にさせて頂きます。
guest

0

ベストアンサー

私ならこう書きます。

Java

1 public int getNum3(Integer num1, Integer num2) { 2 if (num1 == null) return 0; 3 if (num2 == null) return 0; 4 return num2 - num1; 5 }

投稿2017/05/17 14:35

TakeOne

総合スコア6302

退会済みユーザー

退会済みユーザー

2017/05/17 14:57

可読性が優れているんじゃないでしょうか
k499778

2017/05/17 15:10

みなさん回答ありがとうございました。 ご親切なみなさまのアドバイスのおかげで疑問が解消されたと同時に多くの新しい知識や書き方も知ることができました。 BAは一番わかりやすかったという点でこちらの回答を選ばせていただきました。 nullのわずらわしさを払拭してくれるOptionalも興味があるので今後触れていきたいと思います。
kometaroimo

2017/05/18 04:29

美しいコードですねぇ
guest

0

回答がもう出てますので勝手ながら比較部分のコードの指摘を。。。
int型は符号付き数値型です(2147483647 ~ -2147483648)
符号付き数値型の場合は、その最大の差をその型では表現できません。

例)2つのInteger型の最大の差は

上限値Integer.MAX_VALUE
下限値Integer.MIN_VALUE

の時で値は4294967295になります。そのため比較部分と戻り値の型はlongになります。

Java

1 public long getNum3(Integer num1, Integer num2) { 2 if (num1 == null || num2 == null) { 3 return 0; 4 } 5 return (long)num2 - num1; 6 }

getNum3(Integer.MIN_VALUE, Integer.MAX_VALUE); をこの値を引数に渡して見るとと分かりやすいかもーです。

投稿2017/05/17 14:27

編集2017/05/17 14:39
umyu

総合スコア5846

0

koko_uさんが既にご指摘されていますが、パラメタのnull判定をしてどちらかがnullだった場合の

Java

1return num3;

はちょっとどうかなと思います。return 0のほうがベターかなと。

例えばエラーを示す値が9だったとして、その場合、このような方針で似たような関数のリファクタリングをする際に、以下のようなコードにはしないと思います。

Java

1public int getNum3(Integer num1,Integer num2){ 2 int num3 =9; //注目!! 3 if(num1==null&&num2==null){ 4 return num3; 5 } 6 num3 = num2-num1; 7 return num3 ; 8}

Java

1public int getNum3(Integer num1,Integer num2){ 2 int num3 =0; 3 if(num1==null&&num2==null){ 4 num3 = 9; //注目!! 5 return num3; 6 } 7 num3 = num2-num1; 8 return num3 ; 9}

可読性が落ちますし、後者は処理も無駄に増えてしまっています。
エラーや、何も処理しなかったことを示す値が明確に決まっている場合は、その値を直接returnするほうがベターだと思います。

Java

1 2//getNum3 3//パラメタ2-パラメタ1の差を返却する 4//パラメタのどちらかがnullの場合は0を返却する 5public int getNum3(Integer num1,Integer num2){ 6 int num3; 7 if(num1==null&&num2==null){ 8 return 0; 9 } 10 num3 = num2-num1; 11 return num3 ; 12}

あとは、これは投稿用に適当につけた名前だと思いますので本質的な指摘ではないのですが、可読性の観点からはもう少し変数名や関数名ににこだわると良いのではないでしょうか。

Java

1 2//getNumDifference 3//パラメタ2-パラメタ1の差を返却する 4//パラメタのどちらかがnullの場合は0を返却する 5public int getNumDifference(Integer subtrahend,Integer minuend){ 6 int difference; 7 if(subtrahend== null || minuend== null){ 8 return 0; 9 } 10 difference = minuend - subtrahend; 11 return difference; 12}

投稿2017/05/17 14:27

編集2017/05/18 06:11
akabee

総合スコア1947

fuzzball

2017/05/18 06:00

minuendとsubtrahendが逆では?
akabee

2017/05/18 06:10

リファクタリングしていただきありがとうございます。その通りですね。 自戒もこめて修正しておきます。
guest

0

java

1 public int getNum3(Integer num1, Integer num2) { 2 int num3 = 0; 3 if (num1 != null && num2 != null) { 4 num3 = num2 - num1; 5 } 6 return num3; 7 } 8

単純にこれだとどうなるんだろう。

投稿2017/05/17 14:25

toutou

総合スコア2052

0

Java8のOptionalを使うとこんな感じ

java

1public int getNum3(Integer num1,Integer num2){ 2 Optional<Integer> i1 = Optional.ofNullable(num1), 3 i2 = Optional.ofNullable(num2); 4 return i1.flatMap(x -> i2.map(y -> y - x)).orElse(0); 5}

異常を伝えるためにもOptionalで返すべきですね。

java

1public Optional<Integer> getNum3(Integer num1,Integer num2){ 2 Optional<Integer> i1 = Optional.ofNullable(num1), 3 i2 = Optional.ofNullable(num2); 4 return i1.flatMap(x -> i2.map(y -> y - x)); 5}

参考→JavaのOptionalのモナド的な使い方 - 複数のOptional

投稿2017/05/17 14:17

編集2017/05/18 06:09
swordone

総合スコア20677

0

では毛色の違ったこんなのはどうでしょうか。

Java

1public int getNum3(Integer num1, Integer num2) { 2 return (getNum(num1) - getNum(num2)); 3} 4 5public int getNum(Integer n) { 6 return (n != null) n : 0; 7}

--- 追記 ---
調べたらこんなんでいけそう

Java

1public int getNum3(Integer num1, Integer num2) { 2 return (ObjectUtils.defaultIfNull(num1, 0) - ObjectUtils.defaultIfNull(num2, 0)); 3}

--- 追記 ---
ということで、他の方のを参考にしてください。(^_^;

投稿2017/05/17 14:05

編集2017/05/17 14:19
takasima20

総合スコア7468

swordone

2017/05/17 14:14

これだと片方だけnullの時に0を返せない(num1がnull,num2が3だとしたら、0-3で‐3になる)
takasima20

2017/05/17 14:16

おっといけねー。指摘ありがとうございます。
takasima20

2017/05/17 14:33

akabeeさんが書かれてるように、0が正常な計算結果なのかイリーガルな処理結果なのか判別できないってのが難しいとこですよねえ。
takasima20

2017/05/17 14:42

自分的にはTakeOneさんのが分かりやすくていいかな~
guest

0

私ならif文でなく↓の一行で戻り値返しします。

return (NULL != num1 && NULL != num2) ? 0 : num2 - num1;

投稿2017/05/17 13:49

編集2017/05/17 13:50
HogeAnimalLover

総合スコア4888

swordone

2017/05/17 13:54

Javaで大文字のNULLって使えたっけ?
Zuishin

2017/05/17 13:57

null ですね。それと && ではなく || が正しいです。
root_jp

2017/05/17 13:58

使えないですね。
HogeAnimalLover

2017/05/17 14:11 編集

ああ失礼 (null != num1 && null != num2) ? num2 - num1 : 0; ですね。
guest

0

Javaは書いたことないですが。。。

java

1public int getNum3(Integer num1, Integer num2){ 2 3 4 if(num1 == null || num2 == null) { 5 return 0; 6 } 7 8 return num2 - num1; 9 10}

java

1public int getNum3(Integer num1, Integer num2){ 2 3 4 return num1 == null || num2 == null ? 0 : num2 - num1; 5 6 7}

投稿2017/05/17 13:33

編集2017/05/17 14:08
退会済みユーザー

退会済みユーザー

総合スコア0

koko_u

2017/05/17 13:37

=== は JavaScript なんじゃよ...
退会済みユーザー

退会済みユーザー

2017/05/17 13:38

なんだって〜〜〜。。。
退会済みユーザー

退会済みユーザー

2017/05/17 13:39

修正しました笑
koko_u

2017/05/17 13:40

よか。よか。
Zuishin

2017/05/17 13:55

それとやはり && はバグで koko_u さんの指摘通り || にしないといけません。
退会済みユーザー

退会済みユーザー

2017/05/17 14:08

なおしましたん!
guest

0

num1==null&&num2==null ではなく num1==null || num2==nullですよね?書き方は普通だと思います。
私なら、先にリターンする方は return num3;ではなく、直接return 0;と書きますが。

投稿2017/05/17 13:33

koko_u

総合スコア938

koko_u

2017/05/17 14:10

ちなみに、3項演算子はめったに使いません。 > if文のreturnは早く返した方がいいとリファクタリングの本で見た気がするのでその観点で実装しています。 これは、メソッドの実装として 1. 事前チェック(例えば、引数に問題がないかを確かめる)。問題があれば処理をしない。 2. よさそうなら本来やりたかった処理をする という意図が明確になるようにコードを書くべき、ということです。 今回、引数が null であるケースと null でないケースが「並列」ではないので、3項演算子で return 1文でまとめていると、コードレビューで私はNGを出す可能性が高いです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.25%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問