top / index / prev / next / target / source
日記形式でつづる いがぴょんコラム ウェブページです。
では、次に FuzzBuzz実装を短くしていく版を作ってみます。
では、次に FuzzBuzz実装を短くしていく版を作ってみます。
※注意: ここで挙げている例は ブラックユーモアです。
最初に思いつくのは 文字列連結によるソースコードの短縮についてです。 FizzBuzzShort01.java
/**
* FizzBuzz: イギリスの学校の子供たちの遊び
*
* 1から100までの数をプリントする。<br>
* ・3の倍数のときは数の代わりに「Fizz」とプリントする。<br>
* ・5の倍数のときは数の代わりに「Buzz」とプリントする。<br>
* ・3と5両方の倍数の場合には数の代わりに「FizzBuzz」とプリントする。
*/
public class FizzBuzzShort01 {
/**
* エントリポイント。
*
* @param args
* コマンドライン引数。このプログラム内では利用されない。
*/
public static void main(final String[] args) {
// TODO:踏み込んだ共通化を行い、ロジックを組み替えました。
// TODO:マジックナンバーは追放されていません。
for (int number = 1; number <= 100; number++) {
// 3の倍数であるかどうか。
final boolean isMultipleOf3 = (number % 3 == 0);
// 5の倍数であるかどうか。
final boolean isMultipleOf5 = (number % 5 == 0);
final StringBuffer bufMsg = new StringBuffer();
if (isMultipleOf3) {
// 3の倍数のときは「Fizz」を追加する。
bufMsg.append("Fizz");
}
if (isMultipleOf5) {
// 5の倍数のときは「Buzz」を追加する。
bufMsg.append("Buzz");
}
if (!isMultipleOf3 && !isMultipleOf5) {
// 3の倍数でも5の倍数でも無い時には、数をセットする。
bufMsg.append(number);
}
// 生成された文字列をプリントする。
System.out.println(bufMsg.toString());
}
}
}
ロジックの組み替えにより 少しずつ短くなっていきます。
3項演算子を利用すると、if 文を省略でき、もっと短くなります。 FizzBuzzShort02.java
/**
* FizzBuzz: イギリスの学校の子供たちの遊び
*
* 1から100までの数をプリントする。<br>
* ・3の倍数のときは数の代わりに「Fizz」とプリントする。<br>
* ・5の倍数のときは数の代わりに「Buzz」とプリントする。<br>
* ・3と5両方の倍数の場合には数の代わりに「FizzBuzz」とプリントする。
*/
public class FizzBuzzShort02 {
/**
* エントリポイント。
*
* @param args
* コマンドライン引数。このプログラム内では利用されない。
*/
public static void main(final String[] args) {
// TODO:3項演算子を用いて、ロジックを組み替えました。
// TODO:マジックナンバーは追放されていません。
for (int number = 1; number <= 100; number++) {
// 3の倍数であるかどうか。
final boolean isMultipleOf3 = (number % 3 == 0);
// 5の倍数であるかどうか。
final boolean isMultipleOf5 = (number % 5 == 0);
final String strMsg = (isMultipleOf3 ? "Fizz" : "")
+ (isMultipleOf5 ? "Buzz" : "")
+ (!isMultipleOf3 && !isMultipleOf5 ? String
.valueOf(number) : "");
// 生成された文字列をプリントする。
System.out.println(strMsg);
}
}
}
ああ、三項演算子は とても素晴らしい!
ここまで来たら、文字列を格納していた変数を無くすことが出来ます。 FizzBuzzShort03.java
/**
* FizzBuzz: イギリスの学校の子供たちの遊び
*
* 1から100までの数をプリントする。<br>
* ・3の倍数のときは数の代わりに「Fizz」とプリントする。<br>
* ・5の倍数のときは数の代わりに「Buzz」とプリントする。<br>
* ・3と5両方の倍数の場合には数の代わりに「FizzBuzz」とプリントする。
*/
public class FizzBuzzShort03 {
/**
* エントリポイント。
*
* @param args
* コマンドライン引数。このプログラム内では利用されない。
*/
public static void main(final String[] args) {
// TODO:不要な文字列変数を削除しました。また変数名をリファクタリングしました。
// TODO:マジックナンバーは追放されていません。
for (int number = 1; number <= 100; number++) {
// 3の倍数であるかどうか。
final boolean isFizz = (number % 3 == 0);
// 5の倍数であるかどうか。
final boolean isBuzz = (number % 5 == 0);
System.out.println((isFizz ? "Fizz" : "") + (isBuzz ? "Buzz" : "")
+ (!isFizz && !isBuzz ? String.valueOf(number) : ""));
}
}
}
まだ、いろいろ出来そうですが、ひとまずここで手を止めます。
さて、ここで注意しなくてはならないのは、短くしていく版として記述されたソースコードは FizzBuzz 問題 - リファクタリング版 のソースコードよりも JavaVM上での実行効率が低い可能性があるという点です。Java 5 以降の StringBuilderによる内部展開を期待したとしても オブジェクトのゴミが多く発生する分、FizzBuzz 問題 - リファクタリング版 よりも実行効率が悪くなると想定されるからです…。訓練された Javaプログラマーは ソースコードを見ただけで そこで実行した際のメモリゴミの概算ができるものです。行数の多いFizzBuzz 問題 - リファクタリング版のほうが メモリ効率が良いなんて 不思議で皮肉なものですね…。
一方で、いくら短く記述するためとはいえ、15などの数 (3と5の共通の倍数) を導出したり、あるいは isFizz, isBuzzという変数を省略してしまいたい (省略すると演算の回数が増えてしまう) 衝動にかられるかも知れません。しかし それを省略すると 剰余計算の回数が増え、実行効率は低下するように考えられます。
更に、15などという数値を導出してしまうと、そもそも仕様上には現れない 謎のマジックナンバーがソースコード上に現れることになります。このような数値を導出すると、ソースコードが仕様変更に対して脆弱になってしまう点にも注意が必要です。仕様変更のコントロール権を完全に掌握していないのであれば、なるべく「仕様通り」に実装しておくのが肝心なのです。
関連する日記