Javaに対するScalaのメリット

Javaから他の言語に行きたいという悩み

  • Javaのいけてない書き方には正直うんざりしてる。
  • でもRubyに移行する勇気はない。
    • 静的な型チェックがないのは実行時のバグが怖い。
      • 特にウォーターフォールで開発をやってるところにとっては、バグの刈り取りを後工程に先送りすることになるので、動的な言語はいまいち。
      • もっさい開発プロジェクトに、テストファースト開発を額面どおりやることなんて絶対無理です。
  • LispHaskellをやりたいけど、「こんなのをかける天才もいるんだね。俺には関係ねーや。」みたいな人が多い。
  • 今まで書いたJavaのコードが無駄になるのはいやだ。

Scalaの解決策

  • Javaよりもはるかに簡潔に書ける。
  • 静的な型チェック(Javaよりもある意味厳密)をしっかりやってくれる。
  • 最悪、Javaのコードの書き方をそのままScalaの文法に変換するだけでいいので、Javaプログラマにとっての敷居は低い。
  • Javaとの親和性が高い。というか、環境はJavaそのもの。
    • コンパイルしたらJavaのクラスファイルができる。
    • 既存のJavaコードベースとそのまま相互に呼び出せるので、徐々に移行できる。

Scalaの便利なとこ(その1):getter/setterのうんざりを解消する

自分でJavaのプログラムを書いていて一番いらいらするのはgetter/setterの定義。
冗長で見るに耐えない。

Sunが気を利かせて、ライン数の水増し手法を提供してくれたのか?(笑)

ScalaJavaに対するメリットの中では一番くだらないんじゃないかとも思いますが、意外と重要でしかもわかりやすいメリットだと思います。

Java
public class Person {

    private final String name = null; // Javaの慣習では、フィールドに直接アクセスしてはいけないことになっています。
    private final Date birth = null;
    private String phone = null;
    private String address = null;

    public Person(String name, Date birth, String phone, String address) {
        this.name = name;
        this.birth = birth;
        Util.checkPhoneIsValid(phone)
        this.phone = phone;
        this. address = address;
    }

    // 以下、getter, setterの嵐です。

    public String getName() {
        return name;
    } 

    public Date getBirth() {
        return birth;
    } 

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) throws InvalidPhoneNumberException {
        // おっと、電話番号は妥当性をチェックする必要があるんでした。
        Util.checkPhoneIsValid(phone);
        this.phone = phone;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = addressn;
    }
}

...

// Personを使う側
Person p = new Person("Hogera Hogeo", new Date(), "090-0000-0000", "Tokyo");
...
return p.getPhone();
...
// ほげ男くんが携帯電話を買い換えたようです。
p.setPhone("090-1111-1111");
Scala

Scalaだとすっきりしますね。

class Person(val name: String,       // コンストラクタ引数です。
             val birth: Date,        // valやvarをつけると、メンバ変数が自動的に定義されます。
             var phone: String,      // valなら同名のgetterも自動的にできます。
             var address: String) {  // varならsetterも"(名前)_="という名前で自動的にできます。

    // インスタンスの初期化は、クラス直下でやります。
    Util.checkPhoneIsValid(phone)
    Util.checkAddressIsValid(address)

    // 自動的にできたsetterを自前のものに置き換えます。
    // (Javaのようにthrowsを書く必要はありません。)
    def phone_=(phone: String) = {
        Util.checkPhoneIsValid(phone)
        this.phone = phone
    }
}
// このクラスには、Person#name, Person#birth, Person#phone, Person#address, Person#addres_=(String)
// というメソッドがこっそり定義されています。

...

// Personを使う側
val p = new Person("Hogera Hogeo", new Date(), "090-0000-0000", "Tokyo")
...
// フィールドを参照しているように見えますが、実はp.phoneというメソッド呼び出しです。
return p.phone
...
// フィールドに代入しているように見えますが、実はp.phone_=(String)というメソッドの呼び出しです。
p.phone = "090-1111-1111"

...(その2以降は。。。)