日記帳

日記です。

10分でわかるかもしれない Java プログラマのための JavaFX Script 入門

最近なんとなく JavaFX をいじっています.
「今後 RIA のプラットホームとして JavaFX が普及する!」とか全く思ってないけど JavaFX Script というスクリプト言語は結構使えるんじゃないかなぁとかそんな感じです.

とりあえずまだ以下のチュートリアルを読んだ程度.

私がチュートリアルを読んだ限りで理解した範囲での Java との大きな相違点は以下の3つくらいです.

つまりこの3点(というか主にバインディング)とその周辺が JavaFX Script の肝であり JavaFX Script の割と面白い部分だと思います.

そこでこの3点を避けて「いかにもつまらなそうな文法上の Java との違い」だけを解説してみます. Java との差分しか記述していなので Java わからない人は読んでも時間の無駄かもしれません.

変数と定数

変数はvar式で宣言する
var hoge;
定数はdef式で定義する
def fuga = 10;
型名は識別子の後に「:<型名>」のように書く
var message:String = "Hello";
def name:String = "World";
型名は省略すると型推論される
var value = 1;
value = "One"; // compile error!!
変数宣言は式であるため一度に複数の変数を宣言できない
var a, b // compile error!
定数定義は式であるため一度に複数の定数を定義できない
def max = 100, min = 0 // compile error!
変数には値の変更時に実行されるコードとして置換トリガーを定義できる
var name = "hoge" on replace oldName{
	println("name has changed : {oldName} => {name}");
}
name = "fuga";
name has changed :  => hoge
name has changed : hoge => fuga

置換トリガーは面白い部類かもしれない…バインディングのベースかな?

型とリテラル

数値型は整数が Integer 型で実数が Number 型
var i:Integer = 10;
var n:Number = 3.141592653;
文字リテラルがなくてシングルクォートでも文字列リテラルとなる
var greeting = 'Hello';
文字列リテラルで「{}」の内に式を書くことで式展開ができる
var name = "World!";
var message = "Hello, {name}"; // => "Hello, World!";
オブジェクト型の汎用のリテラル表記がある
var p = Person{
	name : "Hoge";
	age : 10;
}
javafx.lang.Duration 型にリテラル表記がある
var d : Duration = 15ms; // 10 miliseconds
var d : Duration = 30s; // 5 seconds
var d : Duration = 5m; // 5 minutes
var d : Duration = 1.5h; // 1.5 hours
javafx.animation.KeyValue 型にリテラル表記がある
var x;
var keyValue = x => 256; // 読み難いけど普通こんな書き型はしないので気にしない
println(keyValue.getClass()); // => class javafx.animation.KeyValue

Duration は「期間」を現わす型. KeyValue は「変数と値のペア」を現わす型.どちらもタイムライン定義でよく使われるっぽい.

特殊なリテラル表記は他にもあるのかな?

関数定義

トップレベルに関数が定義できる
function hello(name:String){
	println("Hello, {name}!");
};
関数の戻り値の型名は後に書く
function message(name:String):String {
	return "Hello, {name}!!";
}

クラス定義

変数宣言や関数定義を class {} の中に書くとクラス定義
class Person{
	var name:String;
	var age:Integer;
	function greeting(name:String):String{
		return "Hello, {name}. My name is {this.name}.";
	}
}

var p = Person{
	name:"JavaFX"
	age:0
}
println(p.greeting("World")); // => Hello, World. My name is JavaFX.

アクセス修飾子

private 修飾子がない(デフォルトアクセスで代替?)
デフォルトアクセスは同一スクリプト内だけからアクセス可能
package : 同一パッケージ内からアクセス可能
protected : Java と同様
public : Java と同様
public-read : 読み込みは public,書込みはデフォルトかpackageかprotectedを指定
public-init : 読み込み初期化は public,初期化以外の書き込みはデフォルトか package もしくは protected を指定

public-read は Java にも欲かったなぁ. 当り前だけど public-read と public-init はメソッドには付かない.

演算子

剰余演算子は「%」ではなく「mod」
剰余代入演算子「%=」がない
論理NOT算子は「!」ではなく「not」
論理AND演算子は「&&」ではなく「and」
論理OR演算子は「||ではなく「or」
ビット演算子「|」,「&」,「^」,「~」がない
条件演算子「?:」がない(if式を使う)
文字列連結の「+」演算子がない
var s:String = "hoge" + "fuga"; // compile error!
キャストは「as <型名>」を後置
var i:Integer = obj.getObject() as Integer

制御構文

ブロックは式でありブロック内の最後の式の値がブロック式の値となる.
空ブロック式は Void 型となる
if は式であり実行された最後の式の値がif式の値となる.
var i = 123;
var message = if(i mod 2 == 0) "Even" else "Odd";
if 節と else 節で異なる型を返してもOK
var i = 123;
var message = if(i mod 2 == 0) "Even" else i;
for は式であり各ループで実行された式の値を要素に持つシーケンスを返す
var a = for(i in [1..4]){ i * i }
println(a) // => [ 1, 4, 9, 16 ]
各ループで異なる型を返してもOK
var a = for(i in [1..4]){ if(i mod 2 == 0) "Hello" else i }
println(a) // => [ 1, Hello, 3, Hello ]
while は式であるが Void 型を持ち値を返さない
break と continue は式であるが Void 型を持ち値を返さない
switch-case がない

if-else で書けということか?

var と def は式であり定義された定数や変数の値を持つ
var hoge = { var fuga = 10; }
println(hoge); // => 10
関数定義と別に関数式もある?
var f = function(arg1, arg2) { return arg1 + arg2; }
var add = f;
add(10, 20);

ECMAScript っぽい表記ですね…

関数式でメソッド定義したら代入でメソッドを置き換えられそう
class Hello{
	var message = function(name) { "Hello, {name}"; }
}
var obj = Hello{}
println(obj.message("World")); // => Hello, World

obj.message = function(name) { "Goodbye, {name}" };
println(obj.message("World")); // => Goodbye, World

まとめ

とりえあず思っていた以上に Java と似ていませんでした.もう少し似せた方が Java プログラマへの敷居が下ってよかったんじゃなかろうか?