摘要:使用表達式,使得應用變得簡潔而緊湊。很多語言等從設計之初就支持表達式。表達式的參數與函數式接口內方法的參數,返回值類型相互對應。更多教程和資料請上騰訊課堂樂字節
Java8 引入Lambda表達式,允許開發者將函數當成參數傳遞給某個方法,或者把代碼本身當作數據進行處理。使用Lambda表達式,使得應用變得簡潔而緊湊。 很多語言(Groovy、Scala等)從設計之初就支持Lambda表達式。但是java中使用的是 匿名內部類代替。最后借助強大的社區力量,找了一個折中的Lambda實現方案,可以實現簡潔而緊湊的語言結構。
一、匿名內部類到Lambda的演化匿名內部類,即一個沒有名字的,存在于一個類或方法內部的類。當我們需要用某個類且只需要用一次,創建和使用和二為一時,我們可以選擇匿名內部類,省掉我們定義類的步驟。
匿名內部類會隱士的繼承一個類或實現一個接口,或者說匿名內部類是一個繼承了該類或者實現了該接口的子類匿名對象。下面看一個匿名內部類的例子
package com.java8; /* 定義和使用匿名內部類 */ public class NoNameClass { public static void main(String[] args) { Model m = new Model(){ @Override public void func() { System.out.println("方法的實現"); } }; m.func(); } } // 需要被實現的接口 interface Model{ void func(); }
等價的Lambda 代碼
package com.java8; /* 定義和使用Lambda 簡化代碼 */ public class NoNameClass { public static void main(String[] args) { Model m = new Model(){()->{ System.out.println("方法的實現"); }}; m.func(); } }
可以看出使用Lambda 表達式替代了匿名內部類代碼,使得代碼更加簡化、緊湊。
1、語法
(parameters) -> expression? 或 ?(parameters) ->{ statements; }
可選類型聲明
不需要聲明參數類型,編譯器可以統一識別參數值。
可選的參數圓括號
一個參數無需定義圓括號,但多個參數需要定義圓括號。
可選的大括號
如果主體包含了一個語句,就不需要使用大括號。
可選的返回關鍵字
如果主體只有一個表達式返回值則編譯器會自動返回值,大括號需要指明表達式返回了一個數值
2、Lambda 表達式示例
使用Lambda時,實現方法可以有參數,也可以有返回值,如果沒指定參數類型,則由編譯器自行推斷得出。
1、無參帶返回值生成[1,10]之間的任意整數
interface Model2{ int func(); } Model2 md2 = () -> {return (int)(Math.random()*10+1)};
Lambda的改寫需要有對應的抽象方法,當沒有參數時需要使用()占位,當表達式只有一行代碼時,可以省略return和{}
以上的Lambda等價于:
Model2 md2 = () -> (int)(Math.random()*10+1);2、帶參帶返回值
返回一個對數字描述的字符串。
interface Model3{ String func(int a); } Model3 md3 = (int a) -> { return "This is a number " + a; };
形參寫在()內即可,參數的類型可以省略,此時將由編譯器自行推斷得出,同時還可以省略()
以上的Lambda等價于:
md3 = a -> "This is a number " + a;
省略了參數類型,小括號,同時連帶實現體的括號和return一并省去。
3、帶多個參數根據輸入的運算符計算兩個數的運算,并返回結果
interface Model4{ String func(int a, int b, String oper); } Model4 md4 = (a, b, s) -> { String res = ""; if("+".equals(s)){ res = ( a+b ) + ""; }else if("-".equals(s)){ res = ( a-b ) + ""; }else if("*".equals(s)){ res = ( a*b ) + ""; }else if("/".equals(s)){ res = ( a/b ) + ""; // 暫不考慮除0的情況 }else{ res = "操作有失誤"; } return res; }; System.out.println(md4.func(1,1,"+")); 以上例子為多個參數的Lambda表達式,其中省略掉了每一個參數的類型,編譯器自動推斷。多條語句時實現體的{}不能省。三、Lambda作為參數
在Java8之前,接口可以作為方法參數傳入,執行時必須提供接口實現類的實例。從java8開始,Lambda可以作為接口方法實現,當作參數傳入,無論從形式上還是實際上都省去了對象的創建。使代碼更加的緊湊簡單高效。
1、定義接口在接口中,必須有且僅有一個抽象方法,以確定Lambda模板
// 無參無返回值的方法 interface LambdaInterface1{ void printString(); } // 帶參無返回值的方法 interface LambdaInterface2{ void printString(String str); }2、定義方法接收參數
在某方法中需要使用接口作為參數
// 無參 public static void testLambda(LambdaInterface1 lam1){ lam1.printString(); } // 帶參 public static void testLambda2(String s,LambdaInterface2 lam2){ lam2.printString(s); }3、Lambda表達式作為參數傳入
// 無參Lambda作為參數 testLambda(()->{ System.out.println("可以簡單,可以復雜"); }); // 帶參Lambda作為參數 testLambdaParam("hello",(a)->{ System.out.println(a); });四、Lambda中使用變量
在Lambda中可以定義自己的局部變量,也可以使用外層方法的局部變量,還可以使用屬性。這一點也不難理解,既然是一個方法的實現,只寫了一個代碼塊,那么使用本身所屬方法的局部變量和類的屬性也并不過分。
public static void main(String[] args) { List五、Lambda類型推斷 1、類型檢查strs = new ArrayList (){ { add("aaa"); add("bbb"); add("ccc"); } }; int j = 1; strs.forEach((str)->{ int i = 0; System.out.println(str + " " + i + " " + j); }); }
Lambda的類型是從使用Lambda的上下文推斷出來的。 Lambda表達式的參數與函數式接口內方法的參數,返回值類型相互對應。Lambda表達式需要的類型,或者說Lambda實現的那個函數式接口稱之為目標類型。
2、類型推斷利用目標類型來檢查一個Lambda是否可以用于某個特定的上下文,推斷Lambda參數的類型。
六、Lambda表達式實戰熱銷商品排序
排序對于久經開發的你來說可能并不陌生,假如原來你做過電商項目,相信對于電商場景下的商品記錄排序操作很有感情,下面我們使用Lambda 來看看熱銷商品排序的操作。
測試數據這里以手機測試數據為例
/** * 實際開發數據通常從數據庫獲取 * 這里使用測試數據 */ Goods g01=new Goods(1,"小米9",1789,200, BigDecimal.valueOf(2500)); Goods g02=new Goods(2,"華為Mate20",5000,3000, BigDecimal.valueOf(7000)); Goods g03=new Goods(3,"OPPO R17",2000,2827, BigDecimal.valueOf(1500)); Goods g04=new Goods(4,"魅族 Note9",2000,1600, BigDecimal.valueOf(1600)); Goods g05=new Goods(5,"一加6T",8000,5000, BigDecimal.valueOf(3500)); Listgoods= Arrays.asList(g01,g02,g03,g04,g05);
Collections.sort 靜態方法實現排序
Collections.sort(goods,(g1,g2)->g1.getSale()-g2.getSale());
List.sort 默認方法實現集合排序
// 使用Lambda 對商品記錄按銷量進行排序 goods.sort((g1,g2)->g1.getSale()-g2.getSale());
Stream.sorted 方法實現元素排序
// 多個條件排序情況 Lambda 配置Stream 銷量+價格排序 銷量相等時按照價格排序
goods =goods.stream().sorted((g1,g2)->g1.getSale()-g2.getSale())
.sorted((g1,g2)->g1.getPrice().compareTo(g2.getPrice()))
.collect(Collectors.toList());
日志輸出優化
?????? 對于項目開發日志打印是一項不可獲取的模塊,無論實在開發階段還是項目部署上線后,日志信息的輸出對于開發人員來以及運維人員來說都是一項重要的參考指標。
日志輸出場景這里以用戶模塊UserService 為例,以下為優化前的日志輸出代碼:
public String login(String userName, String userPwd) { logger.info("UserService 接收到參數-->" + userName + "," + userPwd); /** * 登錄邏輯省略 */ return "login"; } 日志級別設置到debug,在開發階段方便查看后端接收到的參數信息。仔細分析這里的日志代碼,可以看到當日志級別設置為info 時 debug 日志不應該執行輸出操作,同時這里調用debug 方法時,對于傳入的字符串參數需要作對應的拼接操作,才會傳入過來。當訪問的情況在商城項目做活動情況下 這里的情況有可能會變得很糟糕:所有的debug 信息全部輸出 同時會有大量字符串拼接操作,會影響整個應用程序的執行性能。
日志輸出場景這里以用戶模塊UserService 為例,日志輸出代碼優化
輸出日志前判斷日志輸出級別
借助Lambda延遲日志內容輸出
/**
添加info方法
判斷日志打印級別
當條件成立時 輸出日志信息
@param logger
@param message
*/ public void info(Log logger, Suppliermessage){ if(logger.isInfoEnabled()){ logger.info(message.get()); } } public String login(String userName, String userPwd) { //logger.info("UserService 接收到參數-->" + userName + "," + userPwd); // 延遲Lambda 表達式執行 只有確定 info(logger,()->"UserService 接收到參數-->" + userName + "," + userPwd); return "login"; }
Lambda優勢與使用場景
Lambda表達式的引入取代了匿名內部類,使得代碼變得簡潔、緊湊,同時Lambda的惰性特點,在開發時能夠提高應用程序的執行性能。
對于Lambda的應用場景,從代碼結構來說通常是結合函數式接口來使用,使得開發是面向函數來進行編程,也是Java8引入的一種新的思想-函數式編程(后續會介紹)。同時還會結合前面講到的接口默認方法提現到應用開發中。
樂字節原創,轉載請注明出處和作者。
更多教程和資料請上 騰訊課堂:樂字節
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/74739.html
摘要:大家好,我是樂字節的小樂,上一次我們說到了核心特性之函數式接口,接下來我們繼續了解又一核心特性方法引用。方法引用是一種更簡潔易懂的表達式。感謝光臨閱讀小樂的,敬請關注樂字節后續將繼續講述等前沿知識技術。 大家好,我是樂字節的小樂,上一次我們說到了Java8核心特性之函數式接口,接下來我們繼續了解Java8又一核心特性——方法引用。 showImg(https://segmentfaul...
摘要:大家好,上一篇小樂給大家講述了樂字節核心特性表達式,點擊回顧。接下來繼續核心特性之函數式接口。感謝大家欣賞小樂帶來的核心特性之函數式接口,接下來還會更多核心技術講解,請關注樂字節如需要視頻課程,請搜索樂字節騰訊課堂 大家好,上一篇小樂給大家講述了《樂字節-Java8核心特性-Lambda表達式》,點擊回顧。接下來繼續:Java8核心特性之函數式接口。 什么時候可以使用Lambda?通常...
摘要:語法中接口可以包含實現方法,需要使用修飾,此類方法稱為默認方法。核心特性接口默認方法就介紹到這里了,后續小樂會繼續講述核心特性。 JAVA8已經發布很久,是自java5(2004年發布)之后Oracle發布的最重要的一個版本。其中包括語言、編譯器、庫、工具和JVM等諸多方面的新特性,對于國內外互聯網公司來說,Java8是以后技術開發的趨勢。這里主要講解在開發中幾個核心的新特性。(主要從...
摘要:上一篇小樂介紹了新特性函數式接口,大家可以點擊回顧。中引入方法引用新特性用于簡化應用對象方法的調用,方法引用是用來直接訪問類或者實例的已經存在的方法或者構造方法。方法引用是一種更簡潔易懂的表達式。 上一篇小樂介紹了《Java8新特性-函數式接口》,大家可以點擊回顧。這篇文章將接著介紹Java8新特性之方法引用。 Java8 中引入方法引用新特性,用于簡化應用對象方法的調用,?方法引用是...
摘要:大家好,我是樂字節的小樂。需要注意的是很多流操作本身就會返回一個流,所以多個操作可以直接連接起來,如下圖這樣,操作可以進行鏈式調用,并且并行流還可以實現數據流并行處理操作。為集合創建并行流。 大家好,我是樂字節的小樂。說起流,我們會聯想到手機、電腦組裝流水線,物流倉庫商品包裝流水線等等,如果把手機 ,電腦,包裹看做最終結果的話,那么加工商品前的各種零部件就可以看做數據源,而中間一系列的...
閱讀 3035·2023-04-25 20:09
閱讀 3318·2021-11-23 09:51
閱讀 1971·2021-11-22 15:25
閱讀 3348·2021-11-18 10:02
閱讀 2747·2021-09-27 13:56
閱讀 1304·2019-08-30 15:44
閱讀 1149·2019-08-30 13:21
閱讀 3322·2019-08-30 11:05