[英]What is the breakdown for Java's lambda syntax?
請解釋 Java 8 的 lambda 方法的語法。
有很多關於 lambda 函數是什么的解釋,但我找不到對語法的徹底解釋,而且我發現學習正確復制語法非常困難,因為我不明白為什么它們按原樣重新編寫。
這是我遇到的一個常見案例,由 NetBeans 提供:
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new MainAppJFrame();
});
}
因此,不知何故,以下 lambda 表達式解析為匿名Runnable
對象的 run() 方法:
() -> {
// do stuff
}
->
是 lambda 語法正確的,對吧? 大括號只是包含匿名方法代碼。 括號是否為空參數,因為在這種情況下我們正在創建一個Runnable.run()
方法?
這對我來說是相當不清楚的。 我假設編譯器知道根據SwingUtilities.invokeLater(Runnable)
方法預期的類型實例化一個匿名Runnable
嗎? 如果有兩個僅參數列表不同的SwingUtilities.invokeLater
方法會發生什么? 顯然在這種特定情況下沒有,但在其他地方是可能的:
interface ExampleLambdaConsumer {
public void doSomething(Runnable r);
public void doSomething(java.lang.reflect.Method m);
}
class C implements ExampleLambdaConsumer {
// implementations for doSomething methods here
public static void main(String[] args) {
doSomething(() -> {
// lambda method body here
}
}
}
語法是:
arguments -> body
其中arguments
可以是
()
如果可以從上下文推斷出該變量的類型,則為單個變量
括號中的變量序列,帶或不帶類型(或自 Java 11 起,帶var
)。
示例: (x)
, (x, y)
, (int x, int y)
, (var x, var y)
(Java 11+)。
以下無效: (int x, y)
, (x, var y)
, (var x, int y)
和body
可以是表達式或帶有語句的{...}
塊。 表達式(除了方法或構造函數調用)只是簡單返回,即() -> 2
等價於() -> {return 2;}
對於像() -> f()
這樣的 lambda 表達式() -> f()
主體是方法或構造函數調用表達式):
如果f()
返回void
,它們等價於() -> { f(); }
() -> { f(); }
否則,它們等價於() -> { f(); }
() -> { f(); }
或() -> { return f(); })
() -> { return f(); })
。 編譯器從調用上下文推斷它,但通常它更喜歡后者。
因此,如果您有兩種方法: void handle(Supplier<T>)
和void handle(Runnable)
,則:
handle(() -> { return f(); })
和handle(() -> x)
將調用第一個,
handle(() -> { f(); }
將調用第二個,並且
handle(() -> f())
:
如果f()
返回void
或不可轉換為T
的類型,則它將調用第二個
如果f()
返回可轉換為T
的類型,則它將調用第一個
編譯器嘗試將 lambda 的類型與上下文匹配。 我不知道確切的規則,但答案是:
如果有兩個僅參數列表不同的 SwingUtilities.invokeLater 方法會發生什么?
是:這取決於這些參數列表是什么。 如果另一個invokeLater
也恰好有一個參數,並且該參數的類型也是具有void*()
類型方法的接口,那么它會抱怨它無法弄清楚您的意思是哪種方法。
為什么它們是這樣寫的? 嗯,我認為這是因為 C# 和 Scala 中的語法幾乎相同(它們使用=>
而不是->
)。
語法是
(parameter_list_here) -> { stuff_to_do; }
如果它是單個表達式,則可以省略大括號。 如果參數列表是單個參數,則可以省略參數列表周圍的正則括號。
該語法僅適用於所有功能接口。 @FunctionalInterface 注釋告訴編譯器您打算編寫這樣的接口,如果您不滿足要求,則會給出編譯錯誤 - 例如它必須只有 1 個可覆蓋的方法。
@FunctionalInterface
interface TestInterface {
void dostuff();
}
Runnable 也是這樣聲明的。 其他接口不是,它們不能與 lambda 函數一起使用。
既然我們已經使用不帶參數的方法創建了一個新的函數式接口,那么我們如何測試您對簽名中“沖突”的問題?
public class Main {
private void test(Runnable r) {
}
private void test(TestInterface ti) {
}
public static void main(String[] args) {
test(() -> { System.out.println("test");})
}
@FunctionalInterface
interface TestInterface {
void dostuff();
}
}
結果:編譯錯誤:對方法測試的調用不明確。
您會看到,編譯器/VM(如果運行時完成)找到適當的方法及其參數列表,並查看參數是否是功能接口,如果是,則創建該接口的匿名實現。 從技術上講(在字節碼中)它與匿名類不同,但在其他方面是相同的(您不會看到 Main$1.class 文件)。
您的示例代碼(由 Netbeans 提供)也可以替換為
SwingUtilities.invokeLater(MainAppJFrame::new);
順便提一句。 :)
Java 8 中基本上采用了 Lambda 表達式,以將覆蓋過程函數簡化為匿名函數。
它們只是覆蓋舊的 Java 匿名函數的快捷方式。
請參考以下示例:
假設您有接口 A ,它只有一個方法聲明如下:
interface A{
void print();
}
現在使用舊的 Java樣式,我們將以匿名方式覆蓋它,如下所示:
new A() {
@Override
public void print() {
System.out.println("in a print method");
}
};
另外現在使用 java 8 lambda 表達式,我們將使用它,如下所示:
() -> System.out.println("in a print method");
在這里,我們可以通過之前所需的方法參數->
操作,然后重寫后身體->
操作。
我們需要實現的唯一更多設置是我們需要使用@FunctionalInterface聲明接口,如下所示:
@FunctionalInterface
interface A{
void print();
}
注意: - lambda 表達式只能用於只有一個非默認方法的“功能”接口。
語法令人困惑。 它驅使我扭轉局面。 如果不是 Intellij,糾正我我會弄錯的。
編譯正常。
class Scratch {
public static void main(String[] args) {
Predicate<Integer> even = integer -> {return (integer%2 == 0);};
}
}
編譯正常。
class Scratch {
public static void main(String[] args) {
Predicate<Integer> even = integer -> {return integer%2 == 0;};
}
}
不編譯,因為它不再是一個語句。
class Scratch {
public static void main(String[] args) {
Predicate<Integer> even = integer -> {return integer%2 == 0};
}
}
不編譯,因為它不再是一個語句並且 return 語句已被刪除。
class Scratch {
public static void main(String[] args) {
Predicate<Integer> even = integer -> {integer%2 == 0};
}
}
編譯正常。
class Scratch {
public static void main(String[] args) {
Predicate<Integer> even = integer -> integer%2 == 0;
}
}
所以這個故事的寓意是,如果你使用括號里面的內容必須是一個語句,並且它必須返回 Functional 接口單個抽象方法所期望的類型(即唯一一個不是默認值的類型)。
實際上,我為自己寫的比其他任何東西都多,因為它一直困擾着我。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.