Java中的函數式接口

2020-09-30 攻城獅Bilbo

1. 什麼是函數式接口

java中函數式接口中的定義如下:

函數式接口(Functional Interface)就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。

需要注意以下幾點:

  1. JDK1.8中接口支持默認方法,默認方法和靜態方法都不屬於抽象方法,因此,函數式接口可以包含默認方法和抽象方法;
  2. 接口默認繼承java.lang.Object,如果接口顯示聲明覆蓋了Object中方法,也不算抽象方法,例如,toString(),equals()等。

具體參考下面用例:

函數式接口

在上面代碼中只有test1()是抽象方法,test2()是默認方法,toString()是接口默認繼承java.lang.Object的方法,並顯式覆蓋了它,不屬於抽象方法。

2. 註解FunctionalInterface

@FunctionalInterface是 Java 8 新加入的一種接口,用於指明該接口類型聲明是根據 Java 語言規範定義的函數式接口。

這裡需要說明的是:

  1. @FunctionalInterface註解只能標記在"有且僅有一個抽象方法"的接口上。
  2. 一個接口是不是函數式接口與加不加@FunctionalInterface註解無關;
  3. 如果一個接口符合"函數式接口"定義,那麼加不加該註解都沒有影響,加上該註解能夠更好地讓編譯器進行檢查。
  4. 如果編寫的不是函數式接口,但是加上了@FunctionalInterface,那麼編譯器會報錯。

3. Java中的函數式接口

JDK中自帶了一些函數式接口,主要可以分為兩類:

在JDK1.8之前已經存在的函數式接口(包括單不限於這些):

java.lang.Runnablejava.util.concurrent.Callablejava.security.PrivilegedActionjava.util.Comparatorjava.io.FileFilterjava.nio.file.PathMatcherjava.lang.reflect.InvocationHandlerjava.beans.PropertyChangeListenerjava.awt.event.ActionListenerjavax.swing.event.ChangeListener

在JDK1.8之後新增了java.util.function這個包,用來支持函數式編程,這個包中包含了很多函數式接口。

主要舉幾個常用的例子:

Consumer<T>表示接受一個類型為T的參數,並且不返回任何結果。

Consumer

返回結果分別是:

hello world5

Supplier<T>表示無參數,返回一個結果,與Consumer<T>相反。

Supplier

返回結果是一個隨機的UUID

5db0e962-7c90-4cc4-93b4-e50f09970eff

Predicate<T>主要用於對某種類型的數據進行判斷,從而得到一個boolean值結果。

包含一個抽象方法:boolean test(T t);,根據需要實現這個方法自定義判斷規則。

三個默認方法:default Predicate<T> and(Predicate<? super T> other)

default Predicate<T> or(Predicate<? super T> other)

default Predicate<T> negate()

分別對應了與或非操作。

還有一個靜態方法:

static <T> Predicate<T> isEqual(Object targetRef)

故名思義,判斷是否相等。

Pridicate

返回結果分別是:

falsefalsefalsetrue

Function<T, R>接口表示輸入T,期望得到R,T和R可以是相同的類型或者不同類型。

包含一個抽象方法R apply(T t);接收參數T,輸出參數R。

包含兩個默認方法andThen()和compose()方法用來進行組合操作,,可以簡單理解為分別是對輸出結果和輸入再次進行加工操作。

包含一個靜態方法static <T> Function<T, T> identity(),這個靜態方法僅僅是將輸入對象輸出。

Function

輸出結果分別是:

2s3s2S

主要常見的就是這幾類接口,其他的接口基本上都繼承自這幾個接口,借用一張圖,如下:

java.util.function包下的函數式接口

4.總結

在java中我們一般常用的是編程方式屬於命令式編程。函數式編程與命令式編程我個人理解區別在於:在命令式編程中我們輸入的是參數,方法中包含的是處理過程,而函數式編程中我們輸入的是處理過程,也就是說把處理過程作為處理參數傳入到方法中,允許把函數本身作為參數傳入另一個函數,還允許返回一個函數。

相關焦點

  • 這樣理解 Java 中的函數式編程就對了
    面向對象編程範式的優點在於其抽象方式與現實中的概念比較相近。比如,學生、課程、汽車和訂單等這些現實中的概念,在抽象成相應的類之後,我們很容易就能理解類之間的關聯關係。這些類中所包含的屬性和方法可以很直觀地設計出來。函數式編程範式則相對較難理解。
  • 為什麼函數式編程在Java中很危險?
    為什麼函數式編程在Java中很危險呢?(ArrayList.java:167)  at java.util.ArrayList.add(ArrayList.java:351)  at Take25.integers(Take25.java:30)  at Take25.main(Take25.java:9) 當Java輸出後,Clojure如何處理函數,使該函數可返回到每一個int?
  • Java8新特性探索之函數式接口
    為了解決上述問題,Java 8 引入了函數式接口,在 java.util.function 包,它包含一組接口,這些接口是 Lambda 表達式和方法引用的目標類型,每個接口只包含一個抽象方法,稱為函數式方法。
  • 「JAVA8」- 函數式接口看這篇就夠了
    什麼是函數式接口?就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。函數式接口可以被隱式轉換為 lambda 表達式。JDK 1.8 之前已有的函數式接口:java.lang.Runnablejava.util.concurrent.Callablejava.security.PrivilegedActionjava.util.Comparator
  • Java新特性之-函數式編程
    面向對象編程範式的優點在於其抽象方式與現實中的概念比較相近。比如,學生、課程、汽車和訂單等這些現實中的概念,在抽象成相應的類之後,我們很容易就能理解類之間的關聯關係。這些類中所包含的屬性和方法可以很直觀地設計出來。函數式編程範式則相對較難理解。這主要是由於函數所代表的是抽象的計算,而不是具體的實體。因此比較難通過類比的方式來理解。
  • 深入理解Java中的Lambda表達式和函數式編程的關係
    上一篇文章(https://www.toutiao.com/i6824085046475883022/),我們理解了函數式編程基本思想、概念和Java對函數式編程的基本使用。本篇我們來聊聊lambda表達式和函數式編程的關係。當提到 Java 8 的時候,Lambda 表達式總是第一個提到的新特性。
  • Java函數式編程快速入門:Lambda表達式與Stream API
    在Java中,Lambda表達式是有類型的,它是一個interface。確切的說,Lambda表達式實現了一個函數式接口(Functional Interface),或者說,前面提到的一些Lambda表達式都是函數式接口的具體實現。函數式接口是一種interface,並且它只有一個虛函數。
  • 面試不知道JDK1.8函數式接口@FunctionalInterface被鄙視了
    從我們自定義的IHello示例來看,Lambda表達式其實是一種接口類型的數據類型,嚴格的說Lambda表達式的數據類型是:函數式接口,是一種特殊的接口,該接口使用@FunctionalInterface註解來標記(不是必須的,可以不用該註解標記,IHello接口就沒有使用該註解標記, ),並且接口中只能有一個抽象方法,可以有多個靜態方法或者默認方法, 每一個該類型的lambda
  • Java如何支持函數式編程?
    嚴格上來講,函數式編程中的「函數」,並不是指我們程式語言中的「函數」概念,而是指數學「函數」或者「表達式」(例如:y=f(x))。不過,在編程實現的時候,對於數學「函數」或「表達式」,我們一般習慣性地將它們設計成函數。所以,如果不深究的話,函數式編程中的「函數」也可以理解為程式語言中的「函數」。
  • Java中「::」是什麼含義
    在Java 8 中,可以通過 「::」 關鍵字來訪問類的構造方法,對象方法,靜態方法。一般有下面幾種用法。Function<String, String> function = String::toUpperCase;String hello = function.apply("hello");System.out.println(hello); //HELLO原來String::toUpperCase返回的是一個函數式接口
  • 純Java中的函數式編程:Functor和Monad示例
    functor提供的唯一操作是帶有函數f的map()。此函數接收框內的任何內容,對其進行轉換並將結果按原樣包裝到另一個Functors中。請仔細閱讀。Functor <T>始終是一個不可變的容器,因此map不會使執行該操作的原始對象發生突變。相反,它將返回包裝在全新Functors中的結果(或結果-請耐心等待),Functors可能是類型R。
  • Java之Lambda函數式編程應用舉例,鏈式語法「真乾貨來拿走」
    Java之Lambda函數式編程應用舉例,鏈式語法「真乾貨來拿走」 java 8 Lambda函數式編程,像阿里、騰訊這樣的大網際網路公司早就已經使用的技術。學習下jdk8的新特性,對提高開發效率和寫出缺陷更低的代碼都非常有好處,時代在進步程式語言也在進化。
  • 函數式編程簡介—Lambda 表達式
    函數式編程作為一種編程範式,在科學領域,是一種編寫電腦程式數據結構和元素的 方式,它把計算過程當做是數學函數的求值,而避免更改狀態和可變數據。什麼是函數式編程?簡單的回答:一切都是數學函數。函數式程式語言裡也可以有對象,但通常這些對象都是恆定不變的 —— 要麼是函數參數,要什麼是函數返回值。
  • Java 8必將掀起Java函數式編程熱潮
    很明顯,這個版本是過去十年以來推出的最具份量的Java更新,其中囊括了海量新特性,包括默認方法、方法與構造函數引用以及Lambda函數等等。  其中最有趣的一項特性當數全新java.util.streamAPI,它作為Javadoc狀態存在,能夠對元素流進行函數式操作,例如在集合中進行map-reduce變換。
  • Java Stream函數式編程?用過都說好,案例圖文詳解送給你
    Java Stream函數式編程接口最初是在Java 8中引入的,並且與lambda一起成為Java開發的裡程碑式的功能特性,它極大的方便了開放人員處理集合類數據的效率。從筆者之前看過的調查文章顯示,絕大部分的開發者使用的JDK版本是java 8,其中Java Stream和lambda功不可沒。
  • 面試被虐題:說說 JVM 系語言的函數式編程
    ,其實Runnable接口的設計在Java 8之前就有了,還是很有遠見的,在此可以把f看成一個無參無返回值的函數,也算是低配版的函數式編程嘛~所以我們在 Java 8 的編程環境下,經常看到 IDE 提示 new Runnable…… 可以轉化成 lamda 表達式。
  • java8的函數式編程解析
    其實在java8就已經有java的函數式編程寫法,只是難度較大,大家都習慣了對象式用法,但在其它語言中都有函數式的用法,如js,scala,函數式其實是抽象到極致的思想。函數接口java8 函數式編程的入口,每個函數接口都帶有 @FunctionalInterface 注釋,有且僅有一個未實現的方法,表示接收 Lambda 表達式,它們存在的意義在於將代碼塊作為數據打包起來。
  • Java為什麼要使用接口_java接口怎麼使用
    接口(英語:Interface),在JAVA程式語言中是一個抽象類型(Abstract Type),它被用來要求類(Class)必須實現指定的方法,使不同類的對象可以利用相同的界面進行溝通。另外,在Java中,接口類型可用來宣告一個變量,他們可以成為一個空指針,或是被綁定在一個以此接口實現的對象。   其中一個使用接口的優勢是,可以利用他們模擬多重繼承,類在JAVA中不允許多重繼承,所有在JAVA中的類必須而且僅能有一個父類,而java.lang.Object(JAVA類型系統中最頂層的類型)是唯一一個例外。
  • java.util.function.Function
    標註為FunctionalInterface的接口被稱為函數式接口如果一個接口只有一個方法,則編譯器會認為這就是一個函數式接口。是否是一個函數式接口,需要注意的有以下幾點:該註解只能標記在」有且僅有一個抽象方法」的接口上。JDK8接口中的靜態方法和默認方法,都不算是抽象方法。
  • Java反射註解妙用(獲取所有接口說明)
    而權限管理需要用到所有的接口配置,包括接口url地址,接口唯一編碼等。想要收集所有的接口信息,如果工程接口很多,工作量可想而知。這裡用了反射,來獲取所有接口的信息,接口再多,也不過幾秒鐘的事。使用Auth.java接口信息對象主要包括授權地址,權限唯一標識,權限名稱,創建時間,請求方式package