Lambda表達式


Lambda表達式

Lambda表達式支持將代碼塊作為方法參數,Lambda表達式允許使用更簡潔的代碼來創建只有一個抽象方法的接口(函數式接口)的實例。

Lambda表達式代替了匿名內部類的繁瑣語法,不需要new Xxx(){ }這種繁瑣的代碼,不需要指出重寫的方法名字,也不需要給出重寫的方法的返回值類型,只要給出重寫的方法括號以及括號里的形參列表即可

Lambda表達式構成:形參列表;箭頭 -> ;代碼塊。

看一個匿名內部類的代碼

int[] target = {3,-4,6,4};
pa.process(target, new Command()
{
//匿名內部類實例來封裝處理行為
public void process(int[] target)
{
int sum = 0;
for(int tmp : target)
{
sum += tmp;
}
System.out.println("數組元素的總和是:" + sum);
}
});

 

使用Lambda表達式簡化上述匿名內部類代碼

 

int[] array = {3,-4,6,4};
pa.process(array,(int[] target)->{
int sum = 0;
for (int tmp: target)
{
sum += tmp;
}
System.out.println("數組元素的總和是:" + sum);
});

 

介紹幾種Lambda表達式的簡化方法

 形參列表:形參列表允許省略形參類型,如果形參中只有一個參數,可以省略圓括號。

代碼塊:若代碼塊只包含一條語句,可省略代碼塊的花括號,只有一條return語句,可省略return關鍵字。

 

lq.eat(()->System.out.println("蘋果的味道不錯!"));    //不帶形參的匿名方法,一行代碼,省略花括號
lq.drive(weather->
{
System.out.println("今天天氣是:" + weather);
System.out.println("直升機飛行平穩");
}); //一個形參,省略括號,省略類型
lq.test((a,b)->a+ b); //省略類型,一行返回值代碼,省略return,省略花括號

 

 Lambda表達式與函數式接口

Lambda表達式的目標類型必須是“函數式接口function interface”,函數式接口代表只包含一個抽象方法的接口。

在只需要實現一個抽象方法來采用匿名內部類語法來創建函數式接口的實例時,可使用Lambda表達式。可使用Lambda表達式進行賦值,因可被當成對象。

Lambda表達式的目標類型必須是明確的函數式接口,只能為函數式接口創建對象,只能實現一個方法。

為使Lambda表達式的目標類型是一個明確的函數式接口,可將Lambda表達式賦值給函數式接口類型的變量;可將Lambda表達式作為函數式接口類型的參數傳給某個方法;可使用函數式接口對Lambda表達式進行強制類型轉換。

java.uril.function包下的典型的函數式接口:

XxxFuncyion(對指定數據進行轉換處理,轉換方法的處理邏輯由Lambda實現);

XXXConsumer(同上相似,對參數處理,但不會返回處理結果);

XXXSupplier(不輸入參數,按某種邏輯算法(由Lambda實現)返回數據);

XxxxPredicate(用於判斷參數(由Lambda實現)是否滿足特定條件,進行篩選數據)。

 

方法引用與構造器引用

如果Lambda表達式的代碼塊只有一條代碼,可以在代碼塊中使用方法引用和構造器引用。

 

引用類方法

 類名::類方法;

函數式接口中被實現方法的全部參數傳給該類方法作為參數;

(a,b,。。。)-》類名。類方法(a,b,。。。)。

Lambda表達式的代碼塊只有一行調用類方法的代碼,則可用引用類方法代替。

 

Converter  converter1 = from-> Integer.valueOf(from);     //Lambda表達式創建Converter對象
Converter Converter1 = Integer::valueOf; //方法引用代替Lambda表達式

調用Integer類的valueOf()類方法來實現Converter函數式接口中唯一的抽象方法,當調用Converter接口中的唯一的抽象方法時,調用參數將會傳給Integer類的valueOf()類方法。

 

引用特定對象的實例方法

特定對象::實例方法;

函數式接口中被實現方法的全部參數傳給該方法作為參數;

(a,b,。。。)-》特定對象。實例方法(a,b,。。。)。

Lambda表達式的代碼塊只有一行調用“fkit。org”對象的indexOf()實例方法的代碼,則可用引用特定對象的實例方法代替。

 

Converter converter2 = from -> "fkit.org".indexOf(from);    //LaCmbda表達式創建Converter對象
Converter converter2 = "fkit.org"::indexOf; //方法引用代替Lambda表達式,全部參數傳給該方法作為參數

調用“fkit.org”對象的indexOf()實例方法來實現Converter函數式接口中唯一的抽象方法,當調用Converter接口中的唯一的抽象方法時,調用參數將會傳給“fkit.org"對象的indexOf()實例方法。

 

引用某類對象的實例方法

類名::實例方法;

函數式接口中被實現方法的第一個參數 作為調用者,后面的參數全部傳給該方法作為參數;

(a,b,。。。)-》a。實例方法(b,。。。)。

Lambda表達式的代碼塊只有一行a。substring(b,c),則可用引用某類對象的實例方法代替

 

MyTest mt = (a,b,c)->a.subString(b,c);     //根據String、int、int三個參數生成一個String返回值
MyTest mt = String::subString; //函數式接口中被實現方法的第一個參數作為調用者,后面的參數全部傳給該方法作為參數

 當調用MyTest接口中的唯一的抽象方法時,第一個調用參數將做為substring()方法的調用者,剩下的調用參數會作為substring()實例方法的調用參數。

引用構造器

類名:new ;

函數式接口中被實現方法的全部參數傳給該構造器作為參數;

(a,b,。。。)-》new。類名(a,b,。。。)。

 Lambda表達式的代碼塊只有一行new JFrame(a),調用構造器 ,可以用引用構造器代替。

 

YourTest  yt = (String a )-> new JFrame(a );      //Lambda表達式
YourTest yt = JFrame::new ; //函數式接口中被實現的全部參數傳給該構造器作為參

調用YourTest接口中的唯一的抽象方法時,調用參數會傳給JFrame構造器。

當調用YourTest接口中的抽象方法時,實際傳入一個String類型的參數,這個String類型的參數會被傳給JFrame構造器,即確定了是調用JFrame類的帶一個String參數的構造器。

 

總結:Lambda表達式只有一行代碼且該函數式接口中只有一個抽象方法時方可用上述方法。

 

4.Lambda表達式與匿名內部類的聯系和區別

聯系:Lambda表達式與匿名內部類一樣,都可以直接訪問“effectively final ” 的局部變量,以及外部類的成員變量;

Lambda表達式創建的對象與匿名內部類生成的對象一樣,都可以直接調用從接口中繼承的默認方法。

區別:Lambda表達式只能為函數式接口創建實例,而匿名內部類能為任意接口和抽象類以及普通類創建實例;

Lambda表達式代碼塊中不允許調用接口中定義的默認方法,而匿名內部類可以。

 

5.使用Lambda表達式調用Arrays的類方法

Arrays類的有些方法需要Comparator、XxxOperator、XXXFunction等函數式接口的實例,可以使用Lambda表達式使代碼更加簡潔。

Arrays.perallelsort(arr1,(o1,o2)->o1.length() - o2.length()) ;               目標類型為Comparator指定了判斷字符串大小的標准。

 

使用Lambda表達式遍歷集合

Iterable接口中新增的forEach(Consumer action )默認方法  所需參數的類型是一個函數式接口,而Iterable接口是Collection接口的父接口,因此Collection集合也可以調用該方法。

當程序調用Iterable的forEach(Consumer action)遍歷集合元素時,程序會依次將集合元素傳給Consumer的accept(T t)方法(該接口中唯一的抽象方法)。正因為Consumer是函數式接口,因此可以使用Lambda表達式來遍歷集合元素。

 

import java.util.*;
public class CollectionEach { public static void main(String[] args) { // 創建一個集合
        Collection books = new HashSet(); books.add("輕量級Java EE企業應用實戰"); books.add("瘋狂Java講義"); books.add("瘋狂Android講義"); // 調用forEach()方法遍歷集合
        books.forEach(obj -> System.out.println("迭代集合元素:" + obj)); //Lambda表達式,省略圓括號,方括號 } }

 

 

使用Lambda表達式遍歷Iterator

Iterator新增的forEachRemaining(Consumer action )方法 所需的Comsumer參數同樣也是函數式接口。當程序調用Iterator的forEachRemaining(Consumer action )遍歷集合元素時,程序會依次將集合元素傳給Consumer的accept(T t)方法(該接口中唯一的抽象方法)。

import java.util.*;
public class IteratorEach { public static void main(String[] args) {

        // 創建一個集合 Collection books = new HashSet(); books.add("輕量級Java EE企業應用實戰"); books.add("瘋狂Java講義"); books.add("瘋狂Android講義");// 獲取books集合對應的迭代器 Iterator it = books.iterator(); // 使用Lambda表達式(目標類型是Comsumer)來遍歷集合元素 it.forEachRemaining(obj -> System.out.println("迭代集合元素:" + obj)); } }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM