はじめに
最近Kotlinを勉強したりしています。
Kotlinならではの記法をまず学ぼうということでFizzBuzzをKotlinで実装した時に書いたメモを記事になるように修正したものです。
ここでは環境構築については記述していません。
関連サイト
-
Kotlin公式HP
https://kotlinlang.org/ -
FizzBuzz(Wikipedia)
https://ja.wikipedia.org/wiki/Fizz_Buzz
とりあえずJavaでFizzBuzzを書いてみる
色々書き方はありますが、とりあえず直球という感じで書いてみると以下のような感じでしょうか。
今回はこのサンプルを元にしていきます。
public class Main {
public static void main(String[] args) {
for (int i = 1; i <= 100; i++) {
String str = "";
if (i % 3 == 0) {
str += "fizz";
}
if (i % 5 == 0) {
str += "buzz";
}
if(str.isEmpty()) {
str = String.valueOf(i);
}
System.out.println(str);
}
}
}
Kotlinで動くようにしよう
このJavaコードをまずはKotlinのプロジェクトにはっつけてエラーになった箇所について調べていきます。
エラー箇所(for文)
for (int i = 1; i <= 100; i++)
どうやらKotlinではfor文の書き方が違うようでエラーとなりました。
なので、Kotlinでのfor文(ループ処理)について調べていきます。
Referenceを見ると、for文についてはjavaでいうところの拡張for文のみの対応となっているようです。
ということで書き換えたところ、ばっちりエラーは解消されました。
Kotlin的にはfor文というのはIteratorを個別処理させるために存在しているということのようです。
for(i in 1..100)
ちなみに逆順に処理させたい場合はこんな感じに書きます。
for (i in 100 downTo 1)
ついでなのでforについてもうちょっと
せっかくなのでReferenceをもう少し見たところ、Indexの取得もできるようです。
for ((index, i) in (1..100).withIndex())
また、i++のように段階的ではなくi+2のように飛ばし飛ばし処理させたい場合はstepで指定することが可能です。
for (i in 1..100 step 2)
さらに i <=100ではなく i < 100の場合は
for(i in 1 until 100)
と出来るので、今までのfor文で出来たことについて面倒な手順が必要とかはなく、簡単に置き換えることが可能となっているようです。
さらについでなのでListについて調べてみた
KotlinのListはread onlyとMutableのリストが違うものとして明確的に定義されてます。
標準で用意されている初期化メソッドもきちんと分かれています。
listOf()
mutableListOf()
細かいことは調べていないので割愛しますが、Listに対しても拡張が行われていていることが伺えます。
数字のRangeをリストにするだけであればさらに簡単に記述することが出来ます。
(1..100)
これだけで1~100のリストが作成できます。
これとLambdaを使って処理するというのも可能です。
変数宣言
String str = "";
変数の宣言の仕方が違うようでエラーとなっていました。
宣言はよくあるvarとvalで宣言してあげれば型推論して解決してくれるようなので、そのように記述します。
今回は書き換えを行うためvarで宣言します。
var str = "";
型推論のよる型指定ではなくコード上から宣言することも可能です。
val numberInt: Int = 100
val numberLong: Long = 100
特殊な書き方ではないので、紹介だけです。
型変換
str = String.valueOf(i);
kotlinのStringクラスにはvalueOfがないので、エラーになっていますので別の方法で変換する方法があります。
普通にtoStringが使えるのでtoStringだけで大丈夫でした。
str = i.toString();
書き直したコード
以上でエラーがなくなったので、直したコードで動かすとJavaの時と同じ結果が得られると思います。
object Method {
@JvmStatic
fun main(args: Array<String>) {
for (i in 1..100) {
var str: String = "";
if (i % 3 == 0) {
str += "fizz";
}
if (i % 5 == 0) {
str += "buzz";
}
if (str.isEmpty()) {
str = i.toString();
}
System.out.println(str);
}
}
}
更にKotlinぽく
動きましたが、さらにKotlinぽくを考えたいと思います。
文法とprintメソッド
とりあえず文末のセミコロンがいらないのとprintlnは標準で用意されているので、修正します。
object Method {
@JvmStatic
fun main(args: Array<String>) {
for (i in 1..100) {
var str: String = ""
if (i % 3 == 0) {
str += "fizz"
}
if (i % 5 == 0) {
str += "buzz"
}
if (str.isEmpty()) {
str = i.toString()
}
println(str)
}
}
}
表示条件について考える
折角なので現在if文で判定している箇所についてもKotlinぽくしたいと思います。
三項演算子で書く
Kotlinには三項演算子がなく、普通にif文を書くようです。
例えばサンプルのif文をJavaの三項演算子で書くとこんな感じです。
str += i % 3 == 0 ? "fizz" : "";
これをKotlinで書くと
str += if (it % 3 == 0) {"fizz"} else {""}
str += if (i % 3 == 0) "fizz" else ""
となります。
Kotlinでは式として処理ブロックを記述すると、戻り値を設定するブロックとして扱われるようなので、それを利用したものになります(下で書くwhenでも同様のことが可能)。
whenで書く
Kotlinのswitch文的と思っていたのですが、それだけでは留まらずif文のようにも使えたりします。
ということで書き直してみます。
object Method {
@JvmStatic
fun main(args: Array<String>) {
for (i in 1..100) {
when {
i % 15 == 0 -> println("fizzbuzz")
i % 3 == 0 -> println("fizz")
i % 5 == 0 -> println("buzz")
else -> println(i)
}
}
}
}
when文は条件に一度でもひっかかると処理を抜ける仕様になっているので、fizzbuzzを出力する条件を新たに追加しています。
whenに値を与える場合はswitchとして動き、値を与えないとif文的に動くようです。
個人的にはelse ifが幾つも繋がるよりは見やすくてこっちの方が好きです。
elseがないケースはif、あればwhenという使い分けが良いのかなという感じがします。
折角だからLambdaを使ってみる
上でリストの作り方を知ったのでLambdaで処理してみましょう。
fun main(args: Array<String>) {
(1..100).forEach{
when {
it % 15 == 0 -> println("fizzbuzz")
it % 3 == 0 -> println("fizz")
it % 5 == 0 -> println("buzz")
else -> println(it)
}
}
}
とりあえず直球処理でのFizzBuzzをKotlinで書くとこんな感じと思えそうなコードが出来ました。