Java 使用冒號字元的所有方式
一、簡介
許多程式語言出於各種目的使用冒號字元 ( :
。例如,C++ 將其與存取修飾符和類別繼承一起使用,而 JavaScript 將其與物件聲明一起使用。 Python 語言在函數定義、條件塊、循環等方面嚴重依賴它。
事實證明,Java 有一長串冒號字元也出現的地方。在本教程中,我們將全面介紹它們。
2. 增強的for
循環
for
迴圈是程式設計師在任何語言中首先學習的控制語句之一。 Java 中的語法如下:
for (int i = 0; i < 10; i++) {
// do something
}
除此之外,此控制結構非常適合迭代集合或陣列中的項目。事實上,這種用例非常常見,以至於在 Java 1.5 中,該語言引入了一種更緊湊的形式,稱為for-each
循環。
下面是使用for-each
語法迭代數組的範例:
int[] numbers = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9};
for (int i : numbers) {
// do something
}
在這裡我們可以注意到冒號字元。我們應該把它讀作“in” 。因此,上面的循環可以被認為是“對於數字中的每個整數 i”。
除了陣列之外,此語法還可以用於List
和Set
:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
for (Integer i : numbers) {
// do something
}
for-each
循環的目標是消除與標準for
迴圈相關的樣板,從而消除隨之而來的錯誤機會。然而,它是透過犧牲一些功能來實現的,例如跳過索引、反向迭代等。
3. witch
我們在 Java 中發現冒號字元的下一個地方是switch
語句。 switch
語句是一種更易讀且通常更緊湊的if/else
區塊形式。
讓我們來看一個例子:
void printAnimalSound(String animal) {
if (animal.equals("cat")) {
System.out.println("meow");
}
else if (animal.equals("lion")) {
System.out.println("roar");
}
else if (animal.equals("dog") || animal.equals("seal")) {
System.out.println("bark");
}
else {
System.out.println("unknown");
}
}
可以使用switch
語句編寫同一組語句:
void printAnimalSound(String animal) {
switch(animal) {
case "cat":
System.out.println("meow");
break;
case "lion":
System.out.println("roar");
break;
case "dog":
case "seal":
System.out.println("bark");
break;
default:
System.out.println("unknown");
}
}
在這種情況下,冒號字元出現在每個case
的末端。然而,這只適用於傳統的switch
語句。在 Java 12 中,該語言加入了使用表達式的switch
的擴展形式。在這種情況下,我們使用箭頭運算子 ( ->
) 而不是冒號。
4. 標籤
Java 經常被遺忘的功能之一是標籤。雖然有些程式設計師可能對標籤及其與goto
語句的關聯記憶不佳,但在 Java 中,標籤有非常重要的用途。
讓我們考慮一系列嵌套循環:
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (checkSomeCondition()) {
break;
}
}
}
在這種情況下, break
關鍵字會導致內部迴圈停止執行並將控制權傳回外部迴圈。這是因為,預設情況下, break
語句將控制權返回到最近的控制區塊的末端。在本例中,這意味著帶有j
變數的循環。讓我們看看如何使用標籤來改變行為。
首先,我們需要用標籤重寫循環:
outerLoop: for (int i = 0; i < 10; i++) {
innerLoop: for (int j = 0; j < 10; j++) {
if (checkSomeCondition()) {
break outerLoop;
}
}
}
我們有相同的兩個循環,但每個循環現在都有一個label:
。一個名為outerLoop,
另一個名為innerLoop
。我們可以注意到, break
語句現在後面有一個標籤名稱。這指示 JVM 將控制權轉移到該標記語句的結尾,而不是預設行為。結果是, break
語句使用i
變數退出循環,從而有效地結束兩個迴圈。
5. 三元運算符
Java 三元運算子是簡單if/else
語句的簡寫。假設我們有以下程式碼:
int x;
if (checkSomeCondition()) {
x = 1;
}
else {
x = 2;
}
使用三元運算符,我們可以縮短相同的程式碼:
x = checkSomeCondition() ? 1 : 2;
此外,三元運算子可以與其他語句搭配使用,使我們的程式碼更具可讀性:
boolean remoteCallResult = callRemoteApi();
LOG.info(String.format(
"The result of the remote API call %s successful",
remoteCallResult ? "was" : "was not"
));
這節省了我們將三元運算子的結果分配給單獨變數的額外步驟,使我們的程式碼更加緊湊且更易於理解。
6. 方法參考
作為 lambda 專案的一部分在 Java 8 中引入,方法引用也使用冒號字元。方法引用出現在整個 Java 的多個地方,最引人注目的是流。讓我們來看幾個例子。
假設我們有一個名稱列表,並且想要將每個名稱大寫。在 lambda 和方法引用之前,我們可能會使用傳統的for
迴圈:
List<String> names = Arrays.asList("ross", "joey", "chandler");
List<String> upperCaseNames = new ArrayList<>();
for (String name : names) {
upperCaseNames.add(name.toUpperCase());
}
我們可以透過流和方法引用來簡化它:
List<String> names = Arrays.asList("ross", "joey", "chandler");
List<String> upperCaseNames = names
.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
在本例中,我們使用String
類別中的toUpperCase()
實例方法的參考作為map()
操作的一部分。
方法參考對於filter()
操作也很有用,其中方法採用單一參數並傳回boolean
:
List<Animal> pets = Arrays.asList(new Cat(), new Dog(), new Parrot());
List<Animal> onlyDogs = pets
.stream()
.filter(Dog.class::isInstance)
.collect(Collectors.toList());
在本例中,我們使用所有類別可用的isInstance()
方法的方法參考來過濾不同動物類型的清單。
最後,我們也可以使用帶有方法引用的建構子。我們透過將new
運算子與類別名稱和方法參考相結合來做到這一點:
List<Animal> pets = Arrays.asList(new Cat(), new Dog(), new Parrot());
Set<Animal> onlyDogs = pets
.stream()
.filter(Dog.class::isInstance)
.collect(Collectors.toCollection(TreeSet::new));
在這個例子中,我們將過濾後的動物收集到新的TreeSet
而不是List
。
7. 斷言
Java 語言的另一個經常被忽略的特性是斷言。在 Java 1.4 中引入, assert
關鍵字用於測試條件。如果該條件為false
,則會引發錯誤。
讓我們來看一個例子:
void verifyConditions() {
assert getConnection() != null : "Connection is null";
}
在此範例中,如果方法getConnection()
的傳回值為null
,則 JVM 會拋出AssertionError
。冒號後面的String
是可選的。它允許我們提供一條訊息作為條件為false
時拋出的錯誤的一部分。
我們應該記住預設情況下斷言是禁用的。要使用它們,我們必須使用-ea
命令列參數啟用它們。
八、結論
在本文中,我們了解了 Java 如何以各種不同的方式使用冒號字元。具體來說,我們了解如何將冒號字元與增強的for
迴圈、 switch
語句、標籤、三元運算子、方法引用和斷言一起使用。
其中許多功能自 Java 早期就已存在,但隨著語言的變化和添加新功能,又添加了一些功能。
與往常一樣,上面的程式碼範例可以在 GitHub 上找到。