Java 8 教程
“Java 仍然存在,人們開始理解它。”
歡迎閱讀我對 Java 8 的介紹。本文將帶您逐步了解從 Java 7 到 Java 8 的所有新功能。透過快速簡單的程式碼範例,我們可以學習如何使用預設介面、方法引用和
可重複
的註解。在本文的最後,我們將熟悉 Stream API。
沒有不必要的閒聊——只有程式碼和註解!向前!
介面的預設方法
Java 8 允許我們透過添加
default
. 此功能也稱為
擴充方法。下面是第一個範例:
interface Formula {
double calculate(int a);
default double sqrt(int a) {
return Math.sqrt(a);
}
}
除了抽象方法之外
calculate
,介面
Formula
還定義了預設方法
sqrt
。實作該介面的類別只需實作
calculate
.
sqrt
可以直接使用 預設方法。
Formula formula = new Formula() {
@Override
public double calculate(int a) {
return sqrt(a * 100);
}
};
formula.calculate(100);
formula.sqrt(16);
此介面
Formula
作為匿名類別實作。程式碼是多餘的:6行用於實作
sqrt(a * 100)
。正如我們將在下一節中看到的,在 Java 8 中有一種更漂亮的方法來實作單一方法。
Lambda 表達式
讓我們從一個在先前版本的 Java 中對字串清單進行排序的簡單範例開始:
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
靜態方法
Collections.sort
接受一個列表和一個按列表排序順序的比較器。您始終可以建立匿名比較器類別並將其傳遞。在 Java 8 中,您可以編寫更短的形式,即 lambda 表達式,而不是建立匿名類別。
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});
正如您所看到的,程式碼更短且更易於閱讀。但這還可以變得更短:
Collections.sort(names, (String a, String b) -> b.compareTo(a));
對於只有一行的正文,您可以跳過
{}
單字
return
。但你可以讓它更短:
Collections.sort(names, (a, b) -> b.compareTo(a));
Java 編譯器了解參數類型,因此您也可以跳過它們。讓我們更深入地研究 lambda 表達式並了解如何使用它們。
功能介面
lambda 表達式如何適應 Java 類型系統?每個 lambda 對應於介面中所述的類型。因此,函數式介面應該只包含一個抽象方法。該類型的每個 lambda 表達式都將對應於該抽象方法。由於預設方法不是抽象的,因此您可以根據需要在功能介面中自由建立預設方法。如果該介面中只有一個抽象方法,我們也可以使用任意介面作為 lambda 表達式。為了滿足這些要求,您需要添加
@FucntionalInterface
註釋。編譯器知道這一點,如果您想提供多個抽象方法,編譯器會拋出異常。例子:
@FunctionalInterface
interface Converter<F, T> {
T convert(F from);
}
Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted);
請記住,如果
@FunctionalInterface
省略註釋,程式碼也會編譯。
方法與建構函式參考
上面的例子還可以透過使用方法引用變得更小:
Converter<String, Integer> converter = Integer::valueOf;
Integer converted = converter.convert("123");
System.out.println(converted);
Java 8 允許您透過新增
::
. 上面的範例顯示如何引用靜態方法,儘管我們也可以引用非靜態方法:
class Something {
String startsWith(String s) {
return String.valueOf(s.charAt(0));
}
}
Something something = new Something();
Converter<String, String> converter = something::startsWith;
String converted = converter.convert("Java");
System.out.println(converted);
讓我們看看
::
它如何與構造函數一起工作。首先,我們將定義一個具有不同建構函數的範例類別:
class Person {
String firstName;
String lastName;
Person() {}
Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
接下來,我們將定義一個用於建立新物件的介面:
interface PersonFactory<P extends Person> {
P create(String firstName, String lastName);
}
我們不會實現創建工廠,而是將其與構造函數幫助結合在一起
::
:
PersonFactory<Person> personFactory = Person::new;
Person person = personFactory.create("Peter", "Parker");
我們透過創建了到建構函數的連結
Person::new
。Java編譯器將自動選擇與方法簽章相符的正確建構子
PersonFactory.create
。... 待續。不幸的是,我沒有找到保存文章草稿的方法,這真的很奇怪,而且翻譯的時間已經結束了——所以我稍後會完成它。適合所有了解並理解英文的人 -
原始文章。如果您有糾正翻譯的建議,請以任何可用的方式寫下來。
我的 Github 帳戶
GO TO FULL VERSION