JavaFX Scriptプログラム言語を学ぼう

レッスン7:式

は結果の値を評価されるコードの断片で、結合されて"より大きな"式を作ることができます。 JavaFX Scriptプログラム言語は式の言語で、それはループ、条件、ブロックを含む全てが式だという意味です。 いくつかのケースでは(while式のような)式はVoid型で、それは結果の値を返さないことを意味します。 式の下位レベルの考察は JavaFX Script言語リファレンス の中の 6章.式 をご覧ください。

ブロック式


ブロック式は中括弧(訳注:波括弧とも)で囲まれた宣言か式のリストからなり、 セミコロンで区切られています。ブロック式の値は、再度の式の値です。 もしブロック式がひとつも式を含んでいなければ、そのブロック式はVoid型になります。 varとdefは式であることに注意してください。

下のブロック式はいくつかの数値を加えてtotal変数に保存します。

var nums = [5, 7, 3, 9];
var total = {
     var sum = 0;
     for (a in nums) { sum += a };
     sum;
}
println("Total is {total}.");

ここのスクリプトを走らせると以下の出力をします。

Total is 24.

最初の行(var nums = [5, 7, 3, 9];)は、整数の配列を宣言しています。

次の行はtotalと名付けた変数を宣言し、それはこれらの整数の合計を保存します。

ブロック式は下にあるような中括弧の間の全てからなります。

{
var sum = 0;
     for (a in nums) { sum += a };
     sum;
}

このブロックの中で、コードの最初の行は変数sumを宣言しています。 これは配列の数値の合計を保存するためのものです。 二行目(for式)は配列を反復して、それぞれの数値をsumに追加します。 最後の行はブロック式の値(この場合24)を戻り値に設定します。

if式


if式は、もし(if)ある特定の条件が真(true)の場合、あるコードのブロックを実行することで プログラムの流れを管理できます。

例えば、下のスクリプトは年齢を基準にチケットの値段を設定します。 年齢が12から65なら通常料金の$10を払います。 お年寄りと子供は$5で、ただし5歳未満の子供は無料で除きます。

def age = 8;
var ticketPrice;

if (age < 5 ) {
     ticketPrice = 0;
} else if (age < 12 or age > 65) {
     ticketPrice = 5;
} else {
     ticketPrice = 10;
}
println("Age: {age} Ticket Price: {ticketPrice} dollars.");

ageに8が設定されると、スクリプトは以下を出力します。

Age: 8 Ticket Price: 5 dollars.

プログラムは以下のようにこの例を通して流れます。

if (age < 5 ) {
     ticketPrice = 0;
} else if (age  65) {
     ticketPrice = 5;
} else {
     ticketPrice = 10;
}

もしageが5より小さければ、チケットの値段は0になります。

プログラムは次に残りの条件文の検証を通り越して、結果を印字します。

もしageが5より小さくなければ、プログラムは次の (他のif文が後ろに付いているelseキーワードで示されている) 条件文の検証を続行します。

if (age else if (age  65) {
     ticketPrice = 5;
} else {
     ticketPrice = 10;
}

ここはageが5から12の間か、65を超えていればチケットの値段を$5にします。

もしageが12と65の間なら、プログラムはコードのelseキーワードが付いた最後のブロックを流れます。

if (age  65) {
     ticketPrice = 5;
} else {
     ticketPrice = 10;
}

このブロックは、前の条件のいずれも満たさないときだけ実行されます。 ageが12と65の間ならチケットの値段を$10にします。

注意:前のコードはとても簡潔な条件式に崩すことができます。

ticketPrice = if (age < 5) 0 else if (age < 12 or age > 65) 5 else 10;

これをマスターすると便利なテクニックで、後のチュートリアルで再び使われているのを見るでしょう。

範囲式


配列のレッスンでは、一連の数値で配列の数を宣言する省略的な表記法を教えました。

var num = [0..5];

技術的に言えば、[0..5]は範囲式です。デフォルトではその間隔の値は1ですが、 異なる間隔を指定するためにstepキーワードを使うことができます。 例えば、1から10の間の奇数からなる配列を定義するにはこうです。

var nums = [1..10 step 2];
println(nums);

このスクリプトの出力:

[ 1, 3, 5, 7, 9 ]

降順の範囲を作るには、二番目の値が一番目よりも小さいことと、 マイナス値のステップ値を指定していることを確認してください。

var nums = [10..1 step -1];
println(nums);

出力:

[ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 ]

降順の範囲を作るときマイナスのステップ値を与えないなら、 結果として空の配列になります。

次のコードは

var nums = [10..1 step 1];
println(nums);

結果として以下のコンパイル時の警告になります。

range.fx:1: warning: empty sequence range literal, probably not what you meant.
var nums = [10..1 step 1];
           ^
1 warning

ステップ値を省略したときも結果的に空の配列になります。

for式


配列に関係するもう一つの式がfor式です。 このfor式は、配列の要素を繰り返すのに便利なメカニズムを提供します。

次のコードは例を提供します。

var days = ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"];

for (day in days) {
     println(day);
}

このスクリプトの出力:

Mon
Tue
Wed
Thu
Fri
Sat
Sun

この例を個々の部分に分解してみましょう。"for"キーワードからfor式が始まります。

for (day in days) {
     println(day);
}

days変数は入力となる配列の名前で、for式で処理されます。

for (day in days) {
     println(day);
}

day変数は、for式が配列を繰り返すときの現在の要素を保持します。

for (day in days) {
     println(day);
}

day変数は、それをfor式の中で使用する場合、スクリプトの前の部分のどこかで宣言する必要がありません。 さらにdayは、そのループが実行された後にはアクセスできません。 プログラマーはよく一時的な変数に、このような短い(あるいは一文字の)名前を付けます。

前の例では、forが値を返すところを見せませんでした。しかしforは配列を返す式でもあります。 次のコードは、ある配列から他の配列を作る二つの例を、for式を使って示しています。

// Resulting sequence squares the values from the original sequence.
var squares = for (i in [1..10]) i*i; 

// Resulting sequence is ["MON", "TUE", "WED", and so on...]
var capitalDays = for (day in days) day.toUpperCase(); 

toUpperCase関数はStringオブジェクトから提供されていることに注意してください。 APIドキュメントを参考にすることによって、利用可能な関数の全リストを見ることができます。

while式


もう一つのループを作るものがwhile式です。for式が配列の要素を操作するのとは違って、 while式は与えられた条件がfalseになるまで繰り返します。 while式は構文的には式であり、Void型になり、値を返しません。

次は例です。

var count = 0;
while (count < 10) {
    println("count == {count}");
    count++;
} 

このスクリプトの出力:

count == 0
count == 1
count == 2
count == 3
count == 4
count == 5
count == 6
count == 7
count == 8 
count == 9

最初の行はcount変数を宣言して0に初期化しています。

var count = 0;
while (count < 10) {
    println("count == {count}");
    count += 1;
}

次の行からwhile式が始まります。この式は(中括弧の間の)ループを作り、 count < 10がfalseに評価されるまで続きます。

var count = 0;
while (count < 10) {
    println("count == {count}");
    count += 1;
}

while式の本体はcountの現在の値を印字します。そしてcountの値を1でインクリメントします。

var count = 0;
while (count < 10) { 
    println("count == {count}");
    count += 1;

}

countが10に等しくなったら、ループは終わります。無限ループを作るには、 括弧の間にtrueキーワードを置いてください。while(true){}のようにです。

break, continue式


ループに関連する式には、breakとcontinue式があります。 この二つの式は、ループの反復に作用します。 breakはループを完全に中止し、一方、continueは現在の反復だけを中止します。

breakとcontinueは構文的には式です。Void型で値を返しません。

例:

for (i in [0..10]) {
     if (i > 5) {
          break;
     }

     if (i mod 2 == 0) {
          continue;
     }

     println(i);
}

出力:

1
3
5

if式が無ければ、プログラムは単純に0から10の数値を出力します。

最初のif式だけで、プログラムは変数iが5よりも大きくなったらループを中止します。

if (i > 5) {
     break;
}

プログラムは従って1から5までの数値だけを印字します。

二つ目のif式を追加することで、プログラムはループの現在の反復だけを中止して、 次の反復を続行します。

if (i mod 2 == 0) {
     continue;
}

このケースでは、iが偶数(iを2で割ったとき余りがない)のときだけcontinueが実行されます。 これが起きると、println()の実行には絶対到達しないので、値は出力に含まれません。

throw, try, catch, finally式


現実のアプリケーションでは、何らかのイベントがスクリプトの正常な流れの実行を中断することがあります。 例えば、スクリプトがファイルを読み込み、そのファイルが見つからないとき、スクリプトは続行できません。 私達はこの状況を"例外"と呼びます。

注意:例外はオブジェクトです。これらの型は一般的に、それらが表す状況にちなんで名付けられます。 (例えば、FileNotFoundExceptionはファイルが見つからないという状況を表します) しかし、この後出てくる例に指定した例外の設定の定義は、このセクションの範囲を超えています。 私達は一般的な目的に使われる(Javaプログラム言語から借りてきた)Exceptionオブジェクトを使い、 throw, try, catch, finally式のデモをします。

次のスクリプトは例外を投げる関数を定義(そして実行)します。

import java.lang.Exception;

foo();

println("The script is now executing as expected... ");

function foo() {
     var somethingWeird = false;

     if(somethingWeird){
          throw new Exception("Something weird just happened!");
     } else {
          println("We made it through the function.");
     }
}

このスクリプトをそのままで(somethingWeirdにfalseを設定)実行すると、 次のメッセージを出力します。

We made it through the function.
The script is now executing as expected... 

しかし、変数をtrueに変更すると、例外が投げられます。 実行時に、スクリプトは次のメッセージと一緒にクラッシュします。

Exception in thread "main" java.lang.Exception: Something weird just happened!
at exceptions.foo(exceptions.fx:10)
at exceptions.javafx$run$(exceptions.fx:3)

このクラッシュを阻止するには、try/catch式でfoo()の実行を包む必要があります。 その名が暗示するように、これらの式はコードの実行をtryしますが、 何か問題があれば例外をcatchします。

try {
     foo();
} catch (e: Exception) {
     println("{e.getMessage()} (but we caught it)");
}

今ここで、クラッシュの変わりに、プログラムは単純に印字をします。

Something weird just happened! (but we caught it)
The script is now executing as expected... 

finallyブロックというものも(技術的には式ではありませんが)あり、それは常にtry式の後の時点で実行されます。 例外が投げられようがそうでなかろうが関係ありません。 finallyブロックはtryの本体が成功しようが例外が上がろうが関係なく、 やっておくべき後始末を実行するのに使われます。

try {
     foo();
} catch (e: Exception) {
     println("{e.getMessage()} (but we caught it)");
} <strong>finally</strong> {
     println("We are now in the finally expression...");
}

今度はプログラムの出力はこうなります。

Something weird just happened! (but we caught it)
We are now in the finally expression...
The script is now executing as expected... 


Home