エンジニアの将来って?

現在7年目のCOBOL→Java→C#エンジニアが、将来への考えや勉強のアウトプット、たまに腎臓について書くブログです

【Java8】mapToObjメソッドを使ってFizzBuzz問題【ラムダ式】

こんにちは。たいら(@tairaengineer2)です。
今回の記事はJava8のラムダ式のmapToObjメソッドを使ってFizzBuzz問題についての記事です。

FizzBuzz問題とは

3で割り切れる場合は「Fizz」(Bizz Buzzの場合は「Bizz」)、5で割り切れる場合は「Buzz」、両者で割り切れる場合(すなわち15で割り切れる場合)は「Fizz Buzz」(Bizz Buzzの場合は「Bizz Buzz」)を数の代わりに発言しなければならない。

Fizz Buzz - Wikipediaから引用させて頂きました

芸人の世界のナベアツさんのように、3の倍数のときは「Fizz」、5の倍数のときは「Buzz」、15の倍数のときは「Fizz Buzz」を表示させる問題です。

よくプログラム初心者の問題として使われます。

フォルダ構成

フォルダ構成は↓の通りです。

f:id:Tairax:20180828203146p:plain

プログラムの概要

標準入力からFizzBuzzを表示するプログラムです。
今回Javaのプログラムを2つ作りました。
役割は

  • FizzBuzz.java:FizzBuzzを表示する
  • FizzBuzzMain.java:FizzBuzzのメイン

FizzBuzz.java

package fizzBuzz;

import java.util.stream.IntStream;

/**
 * FizzBuzzを表示するクラス
 *
 */
public class FizzBuzz {
	/** 表示する範囲 */
	private int scope = 0;

	/** 定型文 */
	public static final String FIZZ = "Fizz";
	public static final String BUZZ = "Buzz";
	public static final String SIZE_CHECK = "入力してください";
	public static final String NUM_CHECK = "数字を入力してください";

	/**
	 * 与えられた引数が数字かどうか判定
	 * @param args
	 * @return true:数字 , false:数字以外
	 */
	public boolean isArgs(String[] args) {
		// 引数が与えられているか判定
		if (args == null || args.length == 0) {
			System.out.println(SIZE_CHECK);
			return false;
		}

		// 0番目の引数が数字に変換できるかどうか判定
		try {
			this.scope = Integer.parseInt(args[0]);
		} catch (NumberFormatException e) {
			System.out.println(NUM_CHECK);
			return false;
		}

		return true;
	}

	/**
	 * FizzBuzzを表示するメソッド
	 */
	public void printFizzBuzz() {
		IntStream.rangeClosed(1, scope)
		.mapToObj(e ->
			(e % 15 == 0) ? FIZZ + BUZZ :
			(e % 3  == 0) ? FIZZ :
			(e % 5  == 0) ? BUZZ :
			Integer.toString(e))
		.forEach(e -> System.out.println(e));
	}
}

FizzBuzzMain.java

package fizzBuzz;

/**
 * FizzBuzzのメインクラス
 *
 */
public class FizzBuzzMain {
	public static void main(String[] args) {
		FizzBuzz fizzBuzz = new FizzBuzz();

		// 引数を判定
		if(!fizzBuzz.isArgs(args)) {
			return;
		}

		// FizzBuzzを表示
		fizzBuzz.printFizzBuzz();
	}
}

実行結果

では、実際に実行してみましょう!
以下の場合に沿って実行していきます。

  • 何も設定しない場合
  • 文字を引数に設定した場合
  • 数字を設定した場合

何も設定しない場合

↓のように、何も入力しないで実行してみましょう。

f:id:Tairax:20180828204300p:plain

入力してください

何も入力しないと、エラーメッセージが出ます!

文字を引数に設定した場合

↓のように、文字を入力して実行してみましょう。

f:id:Tairax:20180828203916p:plain

数字を入力してください

文字だけの場合も、エラーメッセージが出ます!

数字を設定した場合

↓のように、数字を入力して実行してみましょう。

f:id:Tairax:20180828204659p:plain

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16

想定通り、FizzBuzzを表示することができました!

解説

以下の点を解説します。

  • IntStreamとrangeClosedメソッドについて
  • mapToObjメソッドの中の処理について

IntStreamとrangeClosedメソッドについて

順次および並列の集約操作をサポートするプリミティブint値要素のシーケンスです。

java.util.stream (Java Platform SE 8)から引用させて頂きました

IntStreamを使うと、プリミティブ型のint型のStreamを作ることができます。
そのIntStreamを使って、rangeClosedメソッドで与えられた引数の範囲内のIntStreamを作ります。

rangeClosed
static IntStream rangeClosed(int startInclusive,
                             int endInclusive)
startInclusive(含む)からendInclusive(含む)の範囲でステップ1でインクリメントした値を含む、順序付けされた順次IntStreamを返します。

IntStream (Java Platform SE 8)から引用させて頂きました

今回の場合だったら、1からscopeまでの連続したIntStreamを返してます。

mapToObjメソッドの中の処理について

そもそもmapToObjメソッドとは

mapToObj
<U> Stream<U> mapToObj(IntFunction<? extends U> mapper)
指定された関数をこのストリームの要素に適用した結果から構成される、オブジェクト値のStreamを返します。
これは中間操作です。

IntStream (Java Platform SE 8)

このメソッドを使うと、最初はint型のStreamだったとしても、今回のようにString型のStreamにすることができます。

IntStreamの各数字をmapToObjメソッドの中の処理で、場合分けして、文字列にしています。

.mapToObj(e ->
	(e % 15 == 0) ? FIZZ + BUZZ :
	(e % 3  == 0) ? FIZZ :
	(e % 5  == 0) ? BUZZ :
	Integer.toString(e))

上の処理は三項演算子の処理を長く書いているだけです。
三項演算子で書かない場合、↓の意味になります。

if (e % 15 == 0) {
	FIZZ + BUZZ;
} else if (e % 3  == 0) {
	 FIZZ;
} else if (e % 5  == 0) {
	BUZZ;
} else {
	Integer.toString(e);
}

各数字を場合分けして、文字を返しているだけです。

まとめ:FizzBuzz問題は初心者はぜひチャレンジしてみてください!

以上がラムダ式を使って、FizzBuzz問題を解いてみました。
いかがでしたか?
少しでも、あなたの参考になれば幸いです。
ではでは~(・ω・)ノシ

参考にさせて頂いたサイト様

Javaメソッド参照メモ(Hishidama's Java8 Method Reference Memo)

Java8 Stream API 中間処理 (IntermediateOperation) - abcdefg.....

 

ほかにも勉強記事を書いてます。
よければご参考ください。

【Java】標準入力から判定して、じゃんけんゲームをするプログラム

【Java8】mapメソッドを使ってみよう【ラムダ式】

今までブログで書いたJavaのアウトプット記事のまとめ