Java SE 8新特性导览:使用Lambda Expression进行函数式编程
“ Java SE 8新功能瀏覽 ”系列的這篇文章將深入了解Lambda表達式 。 我將向您展示Lambda表達式的幾種不同用法。 它們都具有功能接口的共同實現。 我將解釋編譯器如何從代碼中推斷信息,例如特定類型的變量以及后臺實際發生的情況。
在上一篇文章“ Java SE 8新功能之旅:Java開發世界中的重大變化 ”中,我談到了在本系列文章中我們將要探索的內容。 首先介紹Java SE 8的 主要功能 ,然后介紹在Microsoft Windows和Apple Mac OS X平臺上JDK8的安裝過程 ,并提供重要的建議和注意事項。
最后,我們經歷了一個由Lambda表達式支持的控制臺應用程序的開發,以確保我們可能已經安裝了Java SE 8。
源代碼托管在我的Github帳戶上:從此處克隆。
Lambda表達是什么?
Java SE 8最著名的新功能也許叫做Project Lambda,它是將Java引入函數式編程領域的一項努力。
用計算機科學術語;
Lambda是一個匿名函數。 即,沒有名稱的功能。
在Java中;
所有函數都是類的成員,被稱為方法。 要創建方法,您需要定義其所屬的類。
Java SE 8中的lambda表達式使您可以使用非常簡潔的語法定義一個類和單個方法,以實現具有單個抽象方法的接口。
讓我們弄清楚這個想法。
Lambda Expressions使開發人員可以簡化和縮短其代碼。 使它更具可讀性和可維護性。 這將導致刪除更多詳細的類聲明 。
讓我們看一些代碼片段。
在此示例中,我的實現將文字字符串輸出到控制臺。 然后,您將獲取該對象,并將其傳遞給線程類的實例。 我將可運行對象實例化為名為r1的對象。 將其傳遞給線程的構造函數并調用線程的start方法。 我的代碼現在將在自己的線程和內存空間中運行。
所以現在,我再次創建一個名為r1的對象,但直接調用該接口的構造方法。 再一次,實現它是單個抽象方法。 然后,我將對象傳遞給線程的構造函數。
我正在聲明具有可運行類型的對象,但現在我使用一行代碼來聲明單個抽象方法實現,然后再次將對象傳遞給線程的構造函數。 您仍在實現可運行的接口并調用它的run方法,但使用的代碼卻少得多。 此外,它可以進行以下改進:
public static void main(String[] args) { new Thread(() -> System.out.println("I am running")).start(); }這是有關Lambda項目的早期規格文檔中的重要報價。
Lambda表達式只能出現在將它們分配給類型為功能接口的變量的位置。
引用布萊恩·格茨
讓我們分解一下以了解發生了什么。
有哪些功能接口?
功能接口是僅具有一個自定義抽象方法的接口。 即,不是從對象類繼承的對象。 Java有許多這樣的接口,例如Runnable,Comparable,Callable,TimerTask等。
在Java 8之前,它們被稱為Single Abstract Method或SAM接口 。 在Java 8中,我們現在將它們稱為功能接口 。
Lambda表達式語法:
這個lambda表達式返回了runnable接口的實現。 它有兩部分,由稱為箭頭標記或Lambda運算符的新語法分開。 lambda表達式的第一部分,在箭頭標記之前,是您要實現的方法的簽名。
在此示例中,這是一個無參數方法,因此僅用括號表示。 但是,如果我要實現一個接受參數的方法,則只需給出參數名稱。 我不必聲明它們的類型。
因為接口只有一個抽象方法,所以數據類型是已知的。 lambda表達式的目標之一就是消除不必要的語法。 表達式的第二部分,在箭頭標記之后,是單個方法主體的實現。
如果僅是一行代碼(如本例所示),則您不需要任何其他內容。 要使用多個語句實現方法主體, 請將它們括在花括號中 。
Runnable r = ( ) -> {System.out.println("Hello!");System.out.println("Lambda!");};Lambda目標:
Lambda表達式可以減少您需要編寫的代碼量以及必須創建和維護的自定義類的數量。
如果您要實現一次使用的接口,那么創建另一個代碼文件或另一個命名類并不總是很有意義。 Lambda表達式可以定義一次匿名實現,以供一次性使用,并顯著簡化代碼。
定義和實例化功能接口
為了開始學習Lambda表達式,我將創建一個全新的功能接口。 一個具有單個抽象方法的接口,然后我將使用Lambda表達式實現該接口。
您可以使用托管在github上的源代碼項目“ JavaSE8-Features”來導航項目代碼。
沒有任何參數的方法,Lambda實現
在我的源代碼中,我實際上將接口放入其自己的以lambda.interfaces結尾的子包中。 我將其命名為HelloInterface接口。為了實現帶有lambda表達式的接口,它必須具有一個抽象方法。 我將聲明一個返回void的公共方法,并將其命名為doGreeting 。 它不會接受任何參數,這是使接口可用于Lambda表達式所需要做的全部工作。 如果需要,可以使用新的注釋,該注釋已添加到Java SE 8中,稱為功能接口 。
/**** @author mohamed_taman*/ @FunctionalInterface public interface HelloInterface {void doGreeting();}現在,我準備在lambda.impl包下創建一個新類UseHelloInterface , 該類將實例化我的功能接口( HelloInterface ),如下所示:
/*** @author mohamed_taman*/public class UseHelloInterface {public static void main(String[] args) {HelloInterface hello = ()-> out.println("Hello from Lambda expression");hello.doGreeting();} }運行文件并檢查結果,它應該運行并輸出以下內容。
------------------------------------------------------------------------------------ --- exec-maven-plugin:1.2.1:exec (default-cli) @ Java8Features --- Hello from Lambda expression ------------------------------------------------------------------------------------因此,當您使用不接受任何參數的單個抽象方法時,代碼就是這樣。 讓我們看一下帶有參數的外觀。
具有任何參數的方法,Lambda實現
在lambda.interfaces下 。 我將創建一個新接口,并將其命名為CalculatorInterface 。 然后,我將聲明一個返回void的公共方法,并將其命名為doCalculate ,它將接收兩個整數參數value1和value2 。
/*** @author mohamed_taman*/@FunctionalInterface public interface CalculatorInterface {public void doCalculate(int value1, int value2);}現在,我準備在lambda.impl包下創建一個新類Use CalculatorInterface ,它將實例化我的功能接口( CalculatorInterface ),如下所示:
public static void main(String[] args) {CalculatorInterface calc = (v1, v2) -> {int result = v1 * v2;out.println("The calculation result is: "+ result);};calc.doCalculate(10, 5);}請注意doCalculate()參數,它們在接口中分別命名為value1和value2,但是您可以在此處為它們命名。 我將其命名為v1和v2。 我不需要在參數名稱前插入int; 該信息是已知的,因為編譯器可以從功能接口方法簽名中推斷出此信息。運行文件并檢查結果,它應該運行并輸出以下內容。
------------------------------------------------------------------------------------ --- exec-maven-plugin:1.2.1:exec (default-cli) @ Java8Features --- The calculation result is: 50 ------------------------------------------------------------------------------------ BUILD SUCCESS始終牢記以下規則:
同樣,您必須遵循該規則,即接口只能具有一個抽象方法 。 然后,可以使用lambda表達式實現該接口及其單一抽象方法。
將內置功能接口與lambda結合使用
前面已經介紹了如何使用lambda表達式實現您自己創建的接口。現在,我將展示具有內置接口的lambda表達式。 屬于Java運行時的接口。 我將使用兩個示例。 我正在一個名為lambda.builtin的程序包中工作,這是練習文件的一部分。 我將從這堂課開始。 UseThreading 。 在此類中,我實現了Runnable接口。 這個接口是Java多線程體系結構的一部分,我的重點是代碼的編寫方式,而不是操作方式。 我將展示如何使用lambda表達式替換這些內部類。 我將注釋掉聲明兩個對象的代碼。 然后,我將重新聲明它們并使用lambdas進行實現。 因此,讓我們開始吧。
public static void main(String[] args) {//Old version// Runnable thrd1 = new Runnable(){// @Override // public void run() { // out.println("Hello Thread 1."); // } //};/******************************************* Using lambda expression inner classes *******************************************/Runnable thrd1 = () -> out.println("Hello Thread 1.");new Thread(thrd1).start();// Old Version/*new Thread(new Runnable() {@Overridepublic void run() {out.println("Hello Thread 2.");}}).start();*//******************************************** Using lambda expression anonymous class ********************************************/new Thread(() -> out.println("Hello Thread 2.")).start();}讓我們看另一個例子。 我將使用比較器 。 比較器是Java中的另一個功能接口,具有單個抽象方法。 此方法是比較方法。打開文件UseComparator類,并檢查代碼的注釋位,這是實際代碼,然后將其重構為lambda表達式。
public static void main(String[] args) {List<string> values = new ArrayList();values.add("AAA");values.add("bbb");values.add("CCC");values.add("ddd");values.add("EEE");//Case sensitive sort operationsort(values);out.println("Simple sort:");print(values);// Case insensetive sort operation with anonymous class/* Collections.sort(values, new Comparator<string>() {@Overridepublic int compare(String o1, String o2) {return o1.compareToIgnoreCase(o2);}}); */// Case insensetive sort operation with Lambdasort(values,(o1, o2) -> o1.compareToIgnoreCase(o2));out.println("Sort with Comparator");print(values);}和以前一樣,它不會為您提供任何性能優勢 。 基本功能完全相同。 無論您聲明自己的類 ,使用內部或匿名內部類還是lambda表達式 ,完全取決于您。
在本系列的下一篇文章中,我們將探討和代碼如何使用lambda表達式, 過濾與謂詞接口的集合 , 遍歷與方法引用 的集合 ,在接口實現的默認方法,并最終實現在接口的靜態方法 遍歷集合 。
資源:
翻譯自: https://www.javacodegeeks.com/2014/07/java-se-8-new-features-tour-functional-programming-with-lambda-expression.html
總結
以上是生活随笔為你收集整理的Java SE 8新特性导览:使用Lambda Expression进行函数式编程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑版奶块闪退(电脑奶块闪退怎么办)
- 下一篇: 充电桩设置(斑马智行充电桩设置)