LoginSignup
16
13

More than 5 years have passed since last update.

とりあえず Better Java として Scala を使ってほしい

Posted at

はじめに

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 を使うと以下のように書けます。

Coin.scala
case class Coin(price: Double, unit: String)

Java でほぼ同等のコードを実現すると以下のようになります。
(正確には hashCode, toString, copy などもオーバーライドするのですが、長くなりすぎるので割愛します)

JavaCoin.java
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 クラスに以下のメソッドを追加します。
unitDollar に揃えるメソッドです。

Coin.scala
  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 を加算するメソッドです。

Coin.scala
  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 を採用する企業も増えていますが、この記事がその一助になれば幸いです。

ソースコード全体

Coin.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)

}
16
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
13