表達式是可以生成某個結果值的代碼段,可以結合使用表達式來生成“更大的”表達式。JavaFX Script
編程語言是表達式語言,這意味著一切(包括循環、條件甚至塊)都是表達式。在某些情況下(如
while
表達式),表達式具有
Void
類型,這意味著它們不返回結果值
塊表達式由一系列聲明或表達式組成,它們括在花括號中并用分號進行分隔。塊表達式的值是最后一個表達式
的值。如果塊表達式中不包含表達式,則其類型為 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}.");
|
運行此腳本將生成以下輸出:
第一行 (var nums = [5, 7, 3, 9];
) 聲明一個整數序列。
第二行聲明一個名為 total
的變量,該變量將用來存放這些整數的和。
隨后的塊表達式由左花括號和右花括號之間的所有內容構成:
{
var sum = 0;
for (a in nums) { sum += a };
sum;
}
|
在該塊內部,第一行代碼聲明一個名為 sum
的變量,該變量將用來存放此序列中各個數字之和。第二行(一個 for
表達式)遍歷該序列,將每個數字與 sum
相加。最后一行設置該塊表達式的返回值(在本例中為 24)。
使用 if
表達式后,僅當特定條件為真時才執行某些代碼塊,從而對程序流
進行定向。
例如,以下腳本基于年齡來設置票價。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 < 12 or age > 65) {
ticketPrice = 5;
} else {
ticketPrice = 10;
}
|
如果 age
小于 5,則票價將設置為 0。
程序隨后將跳過其余條件測試并輸出結果。
如果 age
不小于 5,程序將繼續執行下一個條件測試(由后跟另一個 if
表達式的 else
關鍵字來指示):
if (age < 5 ) {
ticketPrice = 0;
} else if (age < 12 or age > 65) {
ticketPrice = 5;
} else {
ticketPrice = 10;
}
|
如果人的年齡在 5 到 12 歲之間或者大于 65 歲,該程序會將票價設置為 5 美元。
如果人的年齡在 12 到 65 歲之間,程序會流至最后一個代碼塊(用 else
關鍵字進行標記):
if (age < 5 ) {
ticketPrice = 0;
} else if (age < 12 or age > 65) {
ticketPrice = 5;
} else {
ticketPrice = 10;
}
|
只有當前面的所有條件均不滿足時,才會執行此塊。它會針對 12 到 65 歲之間的人將票價設置為 10 美元。
注:可以將上面的代碼縮減成一個非常簡潔的條件表達式:
ticketPrice = if (age < 5) 0 else if (age < 12 or age > 65) 5 else 10;
|
這是一個需要掌握的有用方法,在本教程的后
面部分中還會使用它。
“序列”一課講授了一種用來聲明形成等差數列的數字序列的簡化表示法。
從技術上講,[0..5]
是一個范圍表達式。默認情況下,相鄰值之間的間
隔為 1,但是您可以使用 step
關鍵字來指定一個不同的間隔。例如,定義一個由 1 到 10
之間的奇數構成的序列:
var nums = [1..10 step 2];
println(nums);
|
此腳本的輸出如下所示:
要創建降序范圍,請確保第二個值小于第一個值,并指定一個負的 step 值:
var nums = [10..1 step -1];
println(nums);
|
輸出為:
[ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 ]
|
如果您在創建降序范圍時沒有提供負的 step 值,則會生成一個空序列。
以下代碼:
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
|
如果您完全忽略 step 值,也會生成一個空序列。
另一個與序列有關的表達式是 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);
}
|
當 for
表達式遍歷該序列時,day
變量用來存放當前項:
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 表達式。與作用于序列中項的 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
在語法上是表達式,但它們的類型為 Void
,不返回值。
示例:
for (i in [0..10]) {
if (i > 5) {
break;
}
if (i mod 2 == 0) {
continue;
}
println(i);
}
|
輸出:
如果沒有 if
表達式,該程序將只是輸出 0 到 10 之間的數字。
如果只有第一個 if
表達式,程序將在 i
的值大于 5 時中
斷循環:
因此,程序將僅輸出 1 到 5 之間的數字。
通過添加第二個 if
表達式,程序將僅放棄循環的當前迭代而繼續執行下一
個迭代:
if (i mod 2 == 0) {
continue;
}
|
在這種情況下,只有當 i
為偶數(即 i
能被 2
整除,沒有余數)時才執行 continue
。出現這種情況時,將永遠不會調用 println()
,
因此輸出中將不包含該數字。
在實際的應用程序中,正常的腳本執行流有時會被某個事件中止。例如,如果腳本從某個文件中讀取輸入,但是找不到該文件,該
腳本將無法繼續。我們將這種情況稱為“異常”。
注意:異常是對象。它們的類型通常以它們所表示的情況命名(例如,FileNotFoundException
表示找不到文件的情況)。但是,定義一組特定于即將給出的示例的異常不在本節的討論范圍之內。因此,我們將使用一個通用的 Exception
對象(從 Java 編程語言借用而來)來說明 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 {
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)");
} finally {
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...
天蒼蒼,野茫茫,風吹草底見牛羊