普段Javaを使っている人が、Better Java として、Scalaを触ってみようかという時に
知ってると役に立ちそうな事柄を列挙してみました。極力、javaとscalaで比較できそうな
項目を重点的に挙げています。Scala特有の機能の紹介は少なめです。
- 開発環境
- バージョン(2.7 と 2.8)
- 安定版: 2.7.6 (2009年9月現在)
- 2.7.6にはバグがあるので2.7.5がお勧め
- もうすぐ、2.7.7がでる。2.7.5とほとんど同じ?
- JDK 1.4で動く
- 2.7.* 系列でもソースの互換性があまりない。
- 2.7.* 系列でもバイナリ互換性がないことがあった。
- 生成される、class ファイルの中身がかわった。
- re-compile が必要。
- 2.8(開発中)
- バグfixはこちらの版に対して行われてる
- Java5 以降で動く(Java6推奨のようです)
- 新しい機能(named parameter等)
- コレクションクラスを再設計
- リリース時期はまだ未定
- 新規に大きめのソフトを書き始めるなら 2.8 か?
- コンパイラ(scalac)
- オプションがいっぱい: -X , -Y
- 途中の状態を調べる: -Xshow-phases, -Xprint:cleanup
- 独自に拡張する: compiler plug-in
- 相互に依存する scala と java のソースをコンパイルできる
- 独自のjava parser をもっている
- scalac してから javac する
- fsc(Fast Scala Compiler)
- Javaからscalaを呼ぶ
- scala-library.jar をクラスパスへ
- Scalaのオブジェクトの名前に注意
- scala の class ファイルを javap して確認する
- @scala.reflect.BeanProperty アノテーション
- Javaにやさしい getter , setter
- class Foo(@reflect.BeanProperty var x) で setX, getX を生成。
- scala からは見えない。
- scala から Java を呼ぶ
- Java のメソッドで、scala の予約語になってるものは、` ` で囲む
- 文法(Javaと違うところ)
- import がすごい
- 全ては * でなくて _
- 一行でimport
- import java.awt._, javax.swing._
- 列挙
- import scala.collection.immutable.{Set, Map}
- scala を省略
- import collection.immutable.{Set, Map}
- 一部除外
- import collection.immutable.{Stack => _ , _}
- 別名をつける
- import java.lang.{List => JList}
- 相対import
- import Map._
- Liftweb では頻繁に用いられている。twitter, Inc. の内部規約では使用禁止
- "_root_" package
- 相対importでの曖昧性を除去するために使用する。
- final なインスタンスの field, method をインポート
- class Foo{ def foo(){....}}; val x = (new Foo); import x._
- コメント /* */ をネストできる
- 一つのファイルに複数のパブリックなクラスを定義できる。
- 一つのファイルに複数の package を定義できる。
- なんでも変数名・メソッド名
- UTF-8 , 記号: >> , --> , \\ 等
- $を含んでは駄目。
- 予約語を変数名・メソッド名に使う
- Java を呼び出すのに必要
- 例: Thread.`yield`
- alias
- 型に別名をつける: type Foo = X
- import java.lang.{List => JList}
- this に別名をつける:
- inner Class から外の this を指定するのに便利
- class Foo { self => ... }
- Exception を catch しなくていい
- オーバーライドするときは、override と書かないと駄目
- 配列をつくる: Array(1,2,3)
- 配列へのアクセスは [ ] でなくて ( )
- Array(1,2,3)(0) ⇒ Array(1,2,3).apply(0)
- [ ] は generics の指定のときだけに使う
- : で終わるメソッドは、左右がひっくり返る
- -> でTuple2 のインスタンスを作る
- メソッドに渡すときに便利
- Map.emtpy[Int, Int] + (1, 2) // エラー
- Map.emtpy[Int, Int] + ((1, 2))
- Map.empty[Int, Int] + (1 -> 2)
- default parameter [2.8]
- def sum(n:Int, total:Int=0):Int = if(n==0) total else sum(n-1, n+total)
-
named parameter [2.8]
- def foo(widht:Int, height:Int) = { ... } ; foo(height=100, width=200)
- primitive な型を指定できない
- 無駄なboxed,unboxed操作が生じて効率の悪いコード生成される可能性がある
- @specialized アノテーション [2.8]
- メソッドをネストできる
- メソッドの引数は常に final
- trait で Mix-in な多重継承
- var 変数名:型名 = 式
- val 変数名:型名 = 式
- def メソッド名(引数名:型名):戻りの型 = { ..... }
- class クラス名[型パラメータ](引数名:型名) extends ... with ... { ... }
- 柔軟なアクセス修飾子
- デフォルトはパブリック(public キーワードは無い)
- private[this]
class Foo{ private[this] var x = 1 def foo(f:Foo){ f.x // compile エラー } }
- private[クラス名], private[パッケージ名]
package outerpkg.innerpkg class Outer { class Inner { private[Outer] def f() private[innerpkg] def g() private[outerpkg] def h() } }
- protected[C] は protected または private[C] (間違ってるかも。)
- companionの関係にある object とクラスの場合は private の制限なし
- 記法の簡略化
- 制御構文
- if else, for, while, do while, try catch finallly, match case
- if, try は値を返す
- for は糖衣構文(map, filter, flatmap, foreach) (6.19 For-Comprehensions)
- synchronized, asInstanceOf, isInstanceOf は Any クラスのメソッド
- break, continue は無い ⇒ 必要なら自分で定義する
- while は値を返さない
- 常に 返り値の型は Unit
- 末尾再帰で書き換えましょう
- 遅延評価
- lazy val: 変数の初期化を遅延
- call-by-name(名前呼び出し)
- 独自制御構文の導入
- def If[X](b: => Boolean)(x: => X)(y: =>X) = if(b) x else y
- 可変長引数メソッド
- 4.6.2 Repeated Parameters
- 可変長引数は、Seq[_] として扱う
- def foo(x:Int*){ x.foreach(println(_))}
- リストを可変長引数に適用
- Scala API
- http://www.scala-lang.org/node/216
- scaladoc, vscaladoc(javascriptで検索,開発停止中)
- scala.Predef
- scala.actors
- scala.concurrent
- java のThread を簡単に扱う
- spawn, MailBox, Channel
- scala.collection
- mutable, immutable なコレクションクラスがある
- Predef で、immutable なコレクションがdefault
- scala.xml
- scala.io
- scala.util.parsing.combinator
- class scala.Option
- null って書きたくなくなる
- if(b!=null){...} ⇒ b.foreach(...)
- if(b!=null){...}else{...} ⇒ b.map(...).getOrElse(...)
- class scala.Either
- 二つの状態を保持する。例えば、エラーと正常な値
- The
Either type is often used as an alternative to
scala.Option where Left represents failure (by convention) and
Right is akin to Some.
- trait scala.Iterable
- map, flatMap, foldLeft, foldRight, filter, foreach, mkString, etc.
- trait scala.Functionn, where n は0から22
- trait scala.PartialFunction
- class scala.Tuplen, where n は0から22
- 変数定義
- var: 再代入化
- val: 再代入不化 java の final に相当
- val 変数名:型名 = 式
- 型推論可能であれば型名を省略できる
- クラス実装時には、初期値を必ず指定
- var foo:String = _ で null を指定
- メソッド定義
- def メソッド名(引数名:型名):戻りの型 = { ..... }
- 全てメソッド(組み込み演算子がない)
- メソッドをネストできる
- メソッドの引数は常に final
- 前置単項演算子を定義できる + - ! ~ (6.12.1 Prefix Operations)
- final な末尾再帰関数の最適化
- 相互末尾再帰の最適化[2.8, scala.util.control.TailRec]
- 型
- Any がルートクラス。
- Any に AnyVal と AnyRef
- int, byte 等の primitive 型が無い
- Java の void に相当するのが Unit
- Generics: covariant, contravariant
- Structural types: ダックタイピング
- val foo: { def length():Int } = "foo"
- 関数オブジェクト
- trait Function* を実装したもの
- apply メソッドをもってる
- 型推論で引数の型を省略可
- (x:Int) => x+1 は new Function1[Int,Int]{def apply(x:Int) = x+1 }の省略形
- trait Function1 は、compose andThen を持ってる
- Function.{curried, uncurried}
- メソッドから関数オブジェクトを生成する
- Trait
- 実装をもつ interface
- Mix-in な多重継承
- class Foo extends Bar with T1 with T2
- Trait の指定順に linearlize
- case class
- getter, stter
- apply
- extractor(unapply, unapplySeq)
- 一引数の場合、 andThen, compose
- copy [2.8]
- Function* を自動的に実装する
- object: Singleton の言語レベルのサポート
- Java の static の代わりに
- DynamicVariable: thread safe な状態を持たせる
- 5.4 Object Definitions
- pattern match
- case, for, 代入でパターンマッチ
- val hd::tail = List(1,2,3)
- 正規表現でパターンマッチ
- extractor: unapply, unapplySeq を持つオブジェクト
- case class
- Infix Operation Pattern
- 2引数を持つ extractor を中間に書ける
- case class <--->(x:Int, y:Int) ; foo match{ case x <--> y => }
- パターンマッチに型パラメータは使えない。
- Actor のメッセージのレシーブ
- try catch
- implicit conversion
- xml が値
- XPath ライクなアクセス: \ , \\
- <foo><bar><boo>goo</boo></bar></foo> \\ "boo"
|