はじめに
Scala を使い始めてから2年ほどになります。
私は Scala が大好きなので周りのエンジニアにも勧めたりするのですが、「関数型言語?難しそうだし Java でよくない?」といった忌避感があるみたいです。
確かに、 Scala の機能を余すところなく使うとなると難しいのですが、 Scala の良さを知るだけなら「関数型」について初めから理解しておく必要はありません。
そこで、 Scala の特徴の中でも Java エンジニアにとって魅力的だと思われるところを挙げてみます。
Java の資産が生かせる
Scala には sbt というパッケージマネージャーがあり、 Maven で配布されているライブラリであれば同様に利用できます。
また、プロジェクト内のソースコードでも Scala と Java を共存させることができます。
つまり、ソースコードを一気に置き換える必要はなく、「今度作る新機能だけ Scala でやってみよう」といったことも可能です。
case class
price
(金額)と unit
(単位)を持つ Coin
(硬貨)クラスを作ります。
100円硬貨であれば new Coin(100.0, "Yen")
のように使います。
case class を使うと以下のように書けます。
case class Coin(price: Double, unit: String)
Java でほぼ同等のコードを実現すると以下のようになります。
(正確には hashCode
, toString
, copy
などもオーバーライドするのですが、長くなりすぎるので割愛します)
public class JavaCoin {
public final double price;
public final String unit;
public JavaCoin(double price, String unit) {
this.price = price;
this.unit = unit;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof JavaCoin) {
JavaCoin another = (JavaCoin) obj;
return this.price == another.price && this.unit.equals(another.unit);
}
return false;
}
}
圧倒的に短いですね。
短さは正義だと思います。
ほとんどの要素が式である
プログラムを構成する要素には、 式 と 文 があります。
定義として、値を返すものが式、それ以外は全て文です。
Java では if
, for
, switch
などが文ですが、 Scala ではこれらは全て式です。
具体例は後で説明します。
switch
が強力
Coin
クラスに以下のメソッドを追加します。
unit
を Dollar
に揃えるメソッドです。
def toDollar: Coin =
this match {
case Coin(_, "Dollar") => this
case Coin(_price, "Cent") => Coin(_price * 0.01, "Dollar")
case Coin(_price, "Yen") => Coin(_price * 0.088, "Dollar")
}
match
は Scala における switch
です。
上記のように case class
であれば、プロパティに対してマッチングを行い、変数にバインドするといったことができます。
(本当はポリモーフィズムを使うべきですが、複雑になるので今回は使いません)
また、 return
を書いていませんが、 Scala では何も書かなくても式の結果が戻り値になります。
Scala では match
が式なので戻り値になるわけですね。
演算子のオーバーライド
Coin
クラスに以下のメソッドを追加します。
2つの Coin
を加算するメソッドです。
def +(another: Coin): Coin =
if (this.unit == another.unit)
Coin(this.price + another.price, this.unit)
else
this.toDollar + another.toDollar
unit
が同じであればそのまま加算し、違えば "Dollar"
に揃えて加算します。
以下のように、演算子として使えます。
println(
Coin(1, "Dollar")
+ Coin(10, "Cent")
+ Coin(25, "Cent")
+ Coin(100, "Yen")
+ Coin(500, "Yen")
)
// Coin(54.15,Dollar)
状態を持たない(再代入しない)
ここまで読んでいただくなかでお気づきかもしれませんが、 Scala では基本的に 再代入をしません 。
Java の final
宣言とおなじことです。
「だったら Java で final
使えば良くない?」と思うかもしれませんが、 Scala では言語仕様・標準ライブラリ・サードパーティーライブラリのほとんどがこのルールに従っている、という点が重要です。
再代入しないということは状態を持たないと言い換えることもできます。
状態を持たなければ関数の戻り値は引数によってのみ決定することになり、よりシンプルに考えられるようになります。
デバッガでいちいち変数の値を見たり、状態を想定したテストケースを書く必要が無いなど、多くの恩恵があります。
回りくどい説明になってしまいましたが、このルールの強さは使っているうちに実感できるはずです。
(実はこの項目は関数型の概念に片足を突っ込んでるのですが、一番大事だと思っているところなのであえて説明しました)
おわりに
長くなってしまいましたが、読んでいただきありがとうございました。
まだ紹介したいところはたくさんありますが、キリがないのでここまでにします。
最近は Scala を採用する企業も増えていますが、この記事がその一助になれば幸いです。
ソースコード全体
case class Coin(price: Double, unit: String) {
def toDollar: Coin =
this match {
case Coin(_, "Dollar") => this
case Coin(_price, "Cent") => Coin(_price * 0.01, "Dollar")
case Coin(_price, "Yen") => Coin(_price * 0.088, "Dollar")
}
def +(another: Coin): Coin =
if (this.unit == another.unit)
Coin(this.price + another.price, this.unit)
else
this.toDollar + another.toDollar
}
object Coin extends App {
println(
Coin(1, "Dollar")
+ Coin(10, "Cent")
+ Coin(25, "Cent")
+ Coin(100, "Yen")
+ Coin(500, "Yen")
)
// Coin(54.15,Dollar)
}