簡單理解Java的functional interface

更新於 發佈於 閱讀時間約 7 分鐘

在學Java的人也許多少人會跟小的一樣不是很理解functional interface到底在幹嘛,也覺得語法很多此一舉。希望能夠在此拋磚引玉。

先講結論

重點說在前面。我的理解是,functional interface是為了讓Java像是Python或R等其他語言一樣,可以把一個方法直接分離出來向物件或者參數使用,而不是只能呼叫。請聽小的娓娓道來。

再講原因: 簡單來說是Java對於OOP的堅持的副作用

因為Java是個非常堅持物件導向(Object-oriented programming)的語言,所以語法不會像Javascript, R或Python一樣可以直接定義函數於global environment中:

R的語法:

hello <- function(x) { print('hello')} 然後hello()就可以呼叫

Python的語法:

def hello():
  print("hello")

一樣直接用hello()就可以呼叫

注意到在R跟Python中 hello()都不必掛在某個特定的class中,這點Java等非常強調物件導向的語言就做不到,所以Java提出了functional interface的方案。

先複習一下什麼是interface跟functional interface

interface(介面)一開始被設計出來的功能是為了定規格。在開發程式的時候為了保證某些物件的方法名稱在同一個團隊中的不同開發者能夠維持一致,所以大家會先討論好某些規格,再定義抽象方法出來。抽象方法就是只有名稱,裡面沒有程式碼,而且強迫所有使用該interface的class必須寫出來的方法,否則編譯器就不給過(雖然新版的Java允許Interface裡面定義非抽象方法,例如private跟static methods)。這麼一來團隊就可以把使用同一個interface的方法分給不同人員去開發。

例如某團隊在開發某個網頁程式可以允許使用者利用Google, Facebook, Line帳號來登入,那麼假設這三個不同的登入方式分別是不同的class,也由不同的開發者來撰寫程式碼,那麼如果定義一個interface,叫IAuthenticate裡面有個抽象方法auth(),那麼前端負責開發登入頁面的人員就不需要知道這三個class分別到底怎麼寫,只要知道反正可以呼叫auth()方法就對了。

functional interface的定義是「只有一個抽象方法的interface」。乍看之下這個定義真的很廢,也很令人費解,感覺好像是在限縮interface的能力,從能夠定義很多方法到只能定義一個。

functional interface的用意其實跟interface不一樣

functional interface就是要解決Java沒有辦法簡單地像其他語言一樣把方法當物件傳給其他物件使用或者到時候再決定要不要執行的問題。以前述hello()的例子來說,如果按照Java物件導向的邏輯本來應該寫在某個class裡面:

class HelloPrinter() {
  public void hello() {
    System.out.println("hello!");
  }
}

使用的時候主程式裡面要這樣寫

new HelloPrinter().hello();

整個感覺很多此一舉

所以functional interface就出現了,若我們只管hello()這個方法吃進去什麼跟吐出來什麼(什麼都不吃,也沒有回傳什麼),那麼我們可以定義一個廣用的functional interface,名稱不重要,反正就這個functional interface的方法不接收參數,也不回傳東西,那麼

interface IVoider() {
  void nameDoesntMatter();
}

這個時候就直接傳lambda 方法就好

IVoider hello = () -> {System.out.println("hello");}

訂完IVoider這個functional interface之後,這個所有不吃參數並且不回傳物件的方法是都可以這樣寫存取程物件了,此處hello變成了一個到時候可以當參數傳進別的class的物件了。跟前述的R或Python寫法是否有異曲同工之妙呢?

重點是因為訂了IVoider這個functional interface,所以可以做出一堆所有不吃參數並且不回傳物件的方法是都可以這樣寫存取程物件

IVoider hey = () -> {System.out.println("hey");}
IVoider helloWorld= () -> {System.out.println("helloWorld");}

由此可見,對於functional interface而言,反正使用的時候是直接去指定lambda方法,或method reference(在其他文章中將解釋),所以方法名稱根本沒差,也因此不像interface是用來規範的。

一些Java已經幫你定義好的functional interface

既然functional interface的重點是要像其他語言那樣把方法變成可以傳進別的class的物件,而且方法名稱不重要,只有吃什麼跟吐什麼重要,那麼可以見得當然會有一些已經定義好的functinoal interfaces可以使用。

1. Predicate<T>: 吃 一個任意類型物件當參數,吐出boolean

可以想見常常在需要過濾某些東西的filter中使用。
Predicate<String> sFilter = (s) <- s.startsWith("S");
sFilter變成了一個可以快速檢查字串是不是S開頭的過濾器

2. Consumer<T>: 吃一個任意物件當參數,不吐東西(void)

3. Supplier<T>: 不吃參數,吐出一個任意物件類型T

4. UnaryOperator<T>吃一個物件,吐出一個相同的物件

5. BiFunction<T, T, U>吃兩個類型相同物件,再吐出一個不一定相同類型的物件,會用在Map裡面用來有條件地更新Collection元素中。(待其他文章詳細說明)

以上。















留言
avatar-img
留言分享你的想法!
metal35x-avatar-img
2023/05/06
這篇真的寫得不錯,解答了我的疑惑,非常感謝 !!
avatar-img
寂寞小冬瓜的沙龍
10會員
15內容數
對工程師友善的(目前免費)英文教材 #工程師 #Coding #Python #Django #English #英文 #文法 #語言學習 #程式
2024/04/24
八字是一個非常重要的概念,用於預測個人的命運與性格。八字,又稱作「生辰八字」,是根據一個人出生的年、月、日、時所對應的天干地支來組成的。在八字分析中,十神是理解一個人的性格與命運中不可或缺的元素。 十神的定義 在八字命理中,十神是基於日干(即出生日的天干)與其他天干的相對關係來定義的。這些關係反
2024/04/24
八字是一個非常重要的概念,用於預測個人的命運與性格。八字,又稱作「生辰八字」,是根據一個人出生的年、月、日、時所對應的天干地支來組成的。在八字分析中,十神是理解一個人的性格與命運中不可或缺的元素。 十神的定義 在八字命理中,十神是基於日干(即出生日的天干)與其他天干的相對關係來定義的。這些關係反
2024/04/16
隨因為推論統計邏輯明顯有問題 心理學實驗看到的 p value是 P(Data| Hyptohesis), 也就是假設成立的情況下拿到這樣的資料的機率 以下是大家常見的推論步驟: 先設一個虛無假設 (H0) 拿資料, 算 p value ( = P(Data | Hypothesis)
2024/04/16
隨因為推論統計邏輯明顯有問題 心理學實驗看到的 p value是 P(Data| Hyptohesis), 也就是假設成立的情況下拿到這樣的資料的機率 以下是大家常見的推論步驟: 先設一個虛無假設 (H0) 拿資料, 算 p value ( = P(Data | Hypothesis)
2024/04/15
你好 歡迎來到這個充滿矛盾的地方 由敝人 一個喜歡研究但是不喜歡學術界的博士畢業生 喜歡英文但是討厭講英文的人 主修是統計但是不相信統計 碩士班念心理學但是寧可相信命理 喜歡寫程式但是不喜歡寫應用面的東西 的本人我 歡迎一樣奇怪的你 一樣在找自己的你
2024/04/15
你好 歡迎來到這個充滿矛盾的地方 由敝人 一個喜歡研究但是不喜歡學術界的博士畢業生 喜歡英文但是討厭講英文的人 主修是統計但是不相信統計 碩士班念心理學但是寧可相信命理 喜歡寫程式但是不喜歡寫應用面的東西 的本人我 歡迎一樣奇怪的你 一樣在找自己的你
看更多
你可能也想看
Thumbnail
每年4月、5月都是最多稅要繳的月份,當然大部份的人都是有機會繳到「綜合所得稅」,只是相當相當多人還不知道,原來繳給政府的稅!可以透過一些有活動的銀行信用卡或電子支付來繳,從繳費中賺一點點小確幸!就是賺個1%~2%大家也是很開心的,因為你們把沒回饋變成有回饋,就是用卡的最高境界 所得稅線上申報
Thumbnail
每年4月、5月都是最多稅要繳的月份,當然大部份的人都是有機會繳到「綜合所得稅」,只是相當相當多人還不知道,原來繳給政府的稅!可以透過一些有活動的銀行信用卡或電子支付來繳,從繳費中賺一點點小確幸!就是賺個1%~2%大家也是很開心的,因為你們把沒回饋變成有回饋,就是用卡的最高境界 所得稅線上申報
Thumbnail
全球科技產業的焦點,AKA 全村的希望 NVIDIA,於五月底正式發布了他們在今年 2025 第一季的財報 (輝達內部財務年度為 2026 Q1,實際日曆期間為今年二到四月),交出了打敗了市場預期的成績單。然而,在銷售持續高速成長的同時,川普政府加大對於中國的晶片管制......
Thumbnail
全球科技產業的焦點,AKA 全村的希望 NVIDIA,於五月底正式發布了他們在今年 2025 第一季的財報 (輝達內部財務年度為 2026 Q1,實際日曆期間為今年二到四月),交出了打敗了市場預期的成績單。然而,在銷售持續高速成長的同時,川普政府加大對於中國的晶片管制......
Thumbnail
重點摘要: 6 月繼續維持基準利率不變,強調維持高利率主因為關稅 點陣圖表現略為鷹派,收斂 2026、2027 年降息預期 SEP 連續 2 季下修 GDP、上修通膨預測值 --- 1.繼續維持利率不變,強調需要維持高利率是因為關稅: 聯準會 (Fed) 召開 6 月利率會議
Thumbnail
重點摘要: 6 月繼續維持基準利率不變,強調維持高利率主因為關稅 點陣圖表現略為鷹派,收斂 2026、2027 年降息預期 SEP 連續 2 季下修 GDP、上修通膨預測值 --- 1.繼續維持利率不變,強調需要維持高利率是因為關稅: 聯準會 (Fed) 召開 6 月利率會議
Thumbnail
在 Kotlin 程式語言中,使用關鍵字「interface」來定義介面。在介面中,每個函數預設都是開放的,不需要額外使用「open」關鍵字來宣告。但是,如果你要實作介面中的屬性與函數,就需要使用「override」關鍵字。 介面只定義了方法的名稱、參數和返回值,沒有方法的具體實現。
Thumbnail
在 Kotlin 程式語言中,使用關鍵字「interface」來定義介面。在介面中,每個函數預設都是開放的,不需要額外使用「open」關鍵字來宣告。但是,如果你要實作介面中的屬性與函數,就需要使用「override」關鍵字。 介面只定義了方法的名稱、參數和返回值,沒有方法的具體實現。
Thumbnail
不管用哪種語言開發軟體,除非是那種一個 function 寫個幾萬行的人 (來人啊,把這種人拖去砍了),不然,一般都會根據某些因素,切割成模組或是特定功能的區塊 (一個 class 或是一個 function),但要完成一個特定功能,這些模組或區塊勢必要一起合作,因此這些模組與區塊就發生了關係。
Thumbnail
不管用哪種語言開發軟體,除非是那種一個 function 寫個幾萬行的人 (來人啊,把這種人拖去砍了),不然,一般都會根據某些因素,切割成模組或是特定功能的區塊 (一個 class 或是一個 function),但要完成一個特定功能,這些模組或區塊勢必要一起合作,因此這些模組與區塊就發生了關係。
Thumbnail
👨‍💻簡介 在Go語言中,Interface 是一個重要且強大的概念。Interface提供了一種方式來定義對象之間的契約,讓你可以設計更具有靈活性和可擴展性的程式碼。 你可以把Interface想像成是一種約定,讓不同的東西彼此溝通的方式變得特別靈活和好擴充,告訴程式裡的各個元件彼此要怎麼合作
Thumbnail
👨‍💻簡介 在Go語言中,Interface 是一個重要且強大的概念。Interface提供了一種方式來定義對象之間的契約,讓你可以設計更具有靈活性和可擴展性的程式碼。 你可以把Interface想像成是一種約定,讓不同的東西彼此溝通的方式變得特別靈活和好擴充,告訴程式裡的各個元件彼此要怎麼合作
Thumbnail
方法鏈接和流暢接口在許多現代編程語言和框架中都有使用。這兩個概念有時互相重疊,因為流暢接口通常使用方法鏈接來實現。使用這些技巧可以提高程式碼的可讀性和維護性,使得編碼更符合人類語言的結構。這對於在專案中協同工作的團隊尤為重要,因為它可以讓每個人更容易理解和使用代碼。
Thumbnail
方法鏈接和流暢接口在許多現代編程語言和框架中都有使用。這兩個概念有時互相重疊,因為流暢接口通常使用方法鏈接來實現。使用這些技巧可以提高程式碼的可讀性和維護性,使得編碼更符合人類語言的結構。這對於在專案中協同工作的團隊尤為重要,因為它可以讓每個人更容易理解和使用代碼。
Thumbnail
這篇文章將會講述 Unity C# 中關於 Interface (介面/接口)的基本介紹以及原理說明,最後提供完整的使用流程。
Thumbnail
這篇文章將會講述 Unity C# 中關於 Interface (介面/接口)的基本介紹以及原理說明,最後提供完整的使用流程。
Thumbnail
介紹 在C#2.0時代以前,是沒有泛型的,所以當我們遇到需求是方法內做相同的事情,但因為輸入或輸出的型別不一樣,我們就必須重複寫出類似的程式 以下的例子是=>不同的輸入型別 但卻做相同的事情 =>印出輸入資料 範例: 輸入參數:int或string或DateTime 功能:印出輸入的"數值"
Thumbnail
介紹 在C#2.0時代以前,是沒有泛型的,所以當我們遇到需求是方法內做相同的事情,但因為輸入或輸出的型別不一樣,我們就必須重複寫出類似的程式 以下的例子是=>不同的輸入型別 但卻做相同的事情 =>印出輸入資料 範例: 輸入參數:int或string或DateTime 功能:印出輸入的"數值"
Thumbnail
C# 介面 ( C# Interface ) – (C#教學) – 介面就是類別的接口, 就好像在電插一樣, 不同的電器有同一類與電力的接口. 要編程就像一個布局, 當引用一個class時, 會引用不同的method, property. 如果method的class可以轉換, 就大大簡化了編程.
Thumbnail
C# 介面 ( C# Interface ) – (C#教學) – 介面就是類別的接口, 就好像在電插一樣, 不同的電器有同一類與電力的接口. 要編程就像一個布局, 當引用一個class時, 會引用不同的method, property. 如果method的class可以轉換, 就大大簡化了編程.
Thumbnail
abstract class = 抽象類別 interface = 介面 抽象類別與介面都無法建立物件。 1. 使用abstract關鍵字來建立抽象類別,interface關鍵字建立介面。 interface只能繼承interface,且可以繼承多個:
Thumbnail
abstract class = 抽象類別 interface = 介面 抽象類別與介面都無法建立物件。 1. 使用abstract關鍵字來建立抽象類別,interface關鍵字建立介面。 interface只能繼承interface,且可以繼承多個:
Thumbnail
隨著程式的功能愈來愈複雜,程式碼也愈來愈多,若程式從頭寫到尾沒有任何的段落,可讀性會愈來愈差,甚至會發現同樣的一段程式碼重覆很多遍,因為類似的功能區塊在程式中可能會一再出現。這樣的程式碼不利於多人的協作開發,即使是寫作者本身在一段時間後回來看,可能也難以一眼就掌握程式的主要架構。
Thumbnail
隨著程式的功能愈來愈複雜,程式碼也愈來愈多,若程式從頭寫到尾沒有任何的段落,可讀性會愈來愈差,甚至會發現同樣的一段程式碼重覆很多遍,因為類似的功能區塊在程式中可能會一再出現。這樣的程式碼不利於多人的協作開發,即使是寫作者本身在一段時間後回來看,可能也難以一眼就掌握程式的主要架構。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News