Lambda表達式超詳解

目錄

背景

Lambda表達式的用法

函數式接口

Lambda表達式的基本使用

語法精簡

?變量捕獲

匿名內部類

匿名內部類中的變量捕獲

Lambda的變量捕獲

Lambda表達式在類集中的使用

Collection接口

?List接口

Map接口

總結


背景

Lambda表達式是Java SE 8中的一個重要的新特性.lambda表達式允許你通過表達式來代替功能接口.lambda表達式就和方法一樣,它提供了一個正常的參數列表和一個使用這些參數的主體(body,可以是一個表達式或一個代碼塊).Lambda表達式基于數學中的λ演算得名,也可以稱為閉包.

Lambda表達式的用法

基本語法:(parameters)->expression或(parameters)->{statements;}

Lambda表達式由三個部分組成:

1.parameters:類似方法中的形參列表,這里的參數是函數式接口里的參數.這里的參數類型可以明確聲明也可不聲明而由JVM隱含的判斷.另外當只有一個推斷類型時可以省略掉圓括號.

2.->:可理解為被用于的意思

3.方法體:可以是表達式也可以代碼塊,是在函數式接口里方法的實現.代碼塊可返回一個值或什么都不返回,這里的代碼塊等同于方法中的方法體,如果是表達式,可以返回一個值或者什么都不返回.

舉個栗子:

//1.不需要參數,返回值為2

()->2

//2.接收一個參數(數字類型),返回其兩倍的值

x -> 2 * x

//3.接收兩個參數(數字),并返回它們的和

(x, y) -> x + y

//4.接收2個int型整數,返回它們的乘積

(int x, int y) -> x * y

//5.接收一個string對象,并在控制臺打印,不返回任何值(看起來是返回void)

(String s) -> System.out.println(s)

函數式接口

要了解Lambda表達式,首先需要了解什么是函數式接口,函數接口定義:一個接口有且只有一個抽象方法.

注意:

1.如果一個接口有且只有一個抽象方法,那么該接口就是函數式接口

2.如果我們在某個接口上聲明了@FunctionalInterface注解,那么編譯器就會按照函數式接口的定義來要求該接口,這樣如果有兩個抽象方法,程序編譯就會報錯的.所以,從某種意義上來說,只要你保證你的接口中只有一個抽象方法,你可以不加這個注解.加上就會自動進行檢測的.

定義方式:

@FunctionalInterface
interface NoParameterNoReturn {//注意:只能有一個方法void test();
}

但是這種方法也是可以的:

@FunctionalInterface
interface NoParameterNoReturn {void test();default void test2() {System.out.println("JDK1.8新特性,default默認方法可以有具體的實現");}
}

Lambda表達式的基本使用

首先,我們事先準備好幾個接口:

//無返回值無參數
@FunctionalInterface
interface NoParameterNoReturn {void test();
}//無返回值一個參數
@FunctionalInterface
interface OneParameterNoReturn {void test(int a);
}//無返回值多個參數
@FunctionalInterface
interface MoreParameterNoReturn {void test(int a, int b);
}//有返回值無參數
@FunctionalInterface
interface NoParameterReturn {int test();
}//有返回值一個參數
@FunctionalInterface
interface OneParameterReturn {int test(int a);
}//有返回值多參數
@FunctionalInterface
interface MoreParameterReturn {int test(int a, int b);
}

我們在上面提到過,Lambda可以理解為:Lambda就是匿名內部類的簡化,實際上是創建了一個類,實現了接口,重寫了接口的方法.

沒有使用lambda表達式時的調用方式:

NoParameterNoReturn noParameterNoReturn = new NoParameterNoReturn(){@Overridepublic void test() {System.out.println("hello");}
};

具體使用見以下代碼:

public class TestDemo {public static void main(String[] args) {NoParameterNoReturn noParameterNoReturn = () -> {System.out.println("無參數無返回值");};noParameterNoReturn.test();OneParameterNoReturn oneParameterNoReturn = (int a) -> {System.out.println("一個參數一個返回值: " + a);};oneParameterNoReturn.test(10);MoreParameterNoReturn moreParameterNoReturn = (int a, int b) -> {System.out.println("多個參數無返回值: " + a + " " + b);};moreParameterNoReturn.test(20, 30);NoParameterReturn noParameterReturn = () -> {System.out.println("有返回值無參數! ");return 40;};//接收函數的返回值int ret = noParameterReturn.test();System.out.println(ret);OneParameterReturn oneParameterReturn = (int a) -> {System.out.println("有返回值且有一個參數");return a;};ret = oneParameterReturn.test(50);System.out.println(ret);MoreParameterReturn moreParameterReturn = (int a, int b) -> {System.out.println("有返回值且有多個參數");return a + b;};ret = moreParameterReturn.test(70, 60);System.out.println(ret);}
}

語法精簡

1.參數類型可以省略,如果需要省略,每個參數的類型都需要省略.?

2.參數的小括號里面只有一個參數,那么小括號可以省略.

3.如果方法體中只有一句代碼,那么大括號可以省略.

4.如果方法體中只有一條語句,且是return語句,那么大括號可以省略,且去掉return關鍵字.

?示例代碼:

public static void main(String[] args) {MoreParameterNoReturn moreParameterNoReturn = (a, b) -> {System.out.println("無返回值多個參數,省略參數類型: " + a + " " + b);};moreParameterNoReturn.test(20, 30);OneParameterNoReturn oneParameterNoReturn = a -> {System.out.println("無參數一個返回值, 小括號可以省略: " + a);};oneParameterNoReturn.test(10);NoParameterNoReturn noParameterNoReturn = () -> System.out.println("無參數無返回值,方法體中只有一行代碼");noParameterNoReturn.test();//方法體中只有一條語句,且是return語句NoParameterReturn noParameterReturn = () -> 40;int ret = noParameterReturn.test();System.out.println(ret);}

?變量捕獲

Lambda表達式中存在標量捕獲,了解變量捕獲之后,我們才能更好地理解Lambda表達式的作用域.

Java當中的匿名類中,會存在變量捕獲.

匿名內部類

匿名內部類就是沒有名字的內部類.我們這里只是為了說明變量捕獲,所以,匿名內部類只要會使用即可,那么下面來簡單看看匿名內部類的使用就好了.

舉個簡單的例子:

class Test {public void func() {System.out.println("func()");}
}public class TestDemo {public static void main(String[] args) {Test t = new Test() {@Overridepublic void func() {System.out.println("我是匿名內部類,且重寫了func這個方法! ");}};t.func();}
}

在上述代碼當中的main函數當中,我們看到的就是一個匿名內部類的簡單使用.

匿名內部類中的變量捕獲

在匿名內部類中,在使用內外的變量時,有兩個條件:(要么是常量,要么是未修改的變量)?

來看一下代碼:

public class TestDemo1 {public static void main(String[] args) {int a = 100;Test t1 = new Test() {@Overridepublic void func() {System.out.println("我是匿名內部類,且重寫了func這個方法!");System.out.println("我是捕獲到變量a==" + a + "我是一個常量, 或者是一個沒有改變過值的變量! ");}};t1.func();}
}

在上述代碼當中變量a就是捕獲的變量.這個變量要么是被final修飾,如果不是被final修飾的 你要保證在使用之前沒有修改.如下代碼就是錯誤的代碼.

?

public class TestDemo2 {public static void main(String[] args) {int a = 100;Test t2 = new Test() {@Overridepublic void func() {a = 99;System.out.println("我是匿名內部類,且重寫了func這個方法!");System.out.println("我是捕獲到變量a==" + a + "我是一個常量, 或者是一個沒有改變過值的變量! ");}};}
}

該代碼直接編譯報錯.

Lambda的變量捕獲

lambda其實就是可以認為是匿名內部類的實現

在lambda表達式中也可以進行變量的捕獲,具體我們看一下代碼.

@FunctionalInterface
interface NoParameterNoReturn {void test();
}public class TestDemo3 {public static void main(String[] args) {int a = 10;NoParameterNoReturn noParameterNoReturn = () -> {//a = 99;errorSystem.out.println("捕獲變量" + a);};noParameterNoReturn.test();}
}

Lambda表達式在類集中的使用

?為了能夠讓Lambda和java的集合類更好的一起使用,集合當中,也新增了部分接口,以便與Lambda表達式對接.

對應的接口新增的方法
Collectionremovelf() spliterator() stream() parallelStream() forEach()
ListreplaceAll() sort()
Map

getOrDefault() forEach() replaceAll() putlfAbsent() remove() replace()

computeIfAbsent() computeIfPresent() compute() merge()

以上方法的作用可自行查看javaapi.

Collection接口

forEach()方法演示

該方法在接口Iterable當中,原型如下:

default void forEach(Consumer<? super T> action) {Objects.requireNonNull(action);for(T t : this) {action.accept(t);}
}

該方法表示:對容器中的每個元素執行action指定動作.

public class TestDemo4 {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("Hello");list.add("bit");list.add("hello");list.add("lambda");list.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {//簡單遍歷集合中元素System.out.println(s + " ");}});}
}

?輸出結果:

我們可以修改為如下代碼:

public class TestDemo4 {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("Hello");list.add("bit");list.add("hello");list.add("lambda");//表示調用一個,不帶有參數的方法,其執行花括號內的語句,為原來的函數體內容.list.forEach(s -> System.out.println(s));}
}

?List接口

sort()方法的演示

sort()方法源碼:該方法根據c指定的比較規則對容器元素進行排序.

public void sort(Comparator<? super E> c) {final int expectedModCount = modCount;Arrays.sort((E[]) elementData, 0, size, c);if(modCount != expectedModCount) {throw new ConcurrentModificationExpection();}modCount++;
}

使用示例:

public class TestDemo5 {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("hello");list.add("bit");list.add("lambda");System.out.println(list);list.sort(new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {//這里比較長度return o1.length() - o2.length();}});System.out.println(list);}
}

輸出結果:

?

修改為lambda表達式:

public class TestDemo5 {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("hello");list.add("bit");list.add("lambda");System.out.println(list);//調用帶有兩個參數的方法,且返回長度的差值list.sort((str1, str2) -> str1.length() - str2.length());System.out.println(list);}
}

Map接口

HashMap的forEach()

該方法的原型如下:

default void forEach(BiConsumer<? super K, ? super V> action) {Objects.requireNonNull(action);for(Map.Entry<K, V> entry : entrySet()) {K k;V v;try {k = entry.getKey();v = entry.getValue();} catch {//this usually means the entry is no longer in the map.throw new ConcurrentModificationExpection(ise);}action.accept(k, v);}
}

作用是對Map中的每個映射執行action指定操作.

代碼示例:

public class TestDemo6 {public static void main(String[] args) {HashMap<Integer, String> map = new HashMap<>();map.put(1, "hello");map.put(2, "bit");map.put(3, "hello");map.put(4, "lambda");map.forEach(new BiConsumer<Integer, String>() {@Overridepublic void accept(Integer integer, String s) {System.out.println(integer + " = " + s);}});}
}

輸出結果:

?

使用lambda表達式之后的代碼:

public class TestDemo6 {public static void main(String[] args) {HashMap<Integer, String> map = new HashMap<>();map.put(1, "hello");map.put(2, "bit");map.put(3, "hello");map.put(4, "lambda");map.forEach((k, v) -> System.out.println(k + " = " + v));}
}

總結

lambda表達式的優點很明顯,在代碼層次上來說,使代碼變得非常地簡潔.缺點也不明顯,代碼不易讀.

優點:

1.代碼簡潔,開發迅速

2.方便函數式編程

3.非常容易進行并行運算

4.Java引入了Lambda,改善了集合操作?

缺點:

1.代碼可讀性變差

2.在非并行計算中,很多計算未有傳統的for性能要高

3.不容易進行調試?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/284265.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/284265.shtml
英文地址,請注明出處:http://en.pswp.cn/news/284265.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

用十條命令在一分鐘內檢查Linux服務器性能

這種干活必須要和大家分享的啊。 如果你的Linux服務器突然負載暴增&#xff0c;告警短信快發爆你的手機&#xff0c;如何在最短時間內找出Linux性能問題所在&#xff1f;來看Netflix性能工程團隊的這篇博文&#xff0c;看它們通過十條命令在一分鐘內對機器性能問題進行診斷。 概…

[javaEE] JDBC快速入門

JDBC&#xff1a;Java Data Base Connectivity java數據庫連接 1.組成JDBC的兩個包&#xff1a;主要是接口 java.sql javax.sql 2.相應JDBC的數據庫實現 在tomcat的目錄下面添加mysql-connector-java-5.0.8-bin.jar這個數據庫驅動包 package com.tsh.web;import java.io.IOExce…

【ArcGIS微課1000例】0053:注記(水平、沿直線、跟隨要素、牽引線、彎曲注記)的創建與編輯

文章目錄 一、創建注記1.創建注記要素類2. 水平注記3. 沿直線4. 隨沿要素5. 沿引線6. 彎曲二、修改注記1. 復制粘貼2. 移動注記3. 旋轉注記4. 刪除注記5. 堆疊和取消堆疊6. 向注記添加引線7. 將注記轉換為多部分8. 編輯關聯要素的注記一、創建注記 注記的創建方法參考:【ArcG…

定制.NET 6.0的依賴注入

本章是《定制ASP NET 6.0框架系列文章》的第三篇。在本章&#xff0c;我們將學習ASP.NET Core的依賴項注入&#xff08;DI&#xff09;以及如何自定義它。我們將討論以下主題&#xff1a;使用不同的DI容器探索ConfigureServices方法使用其他的ServiceProviderScrutor簡介技術準…

50 個 Redis 必備知識:基礎知識,架構、調優和監控知識及難點解決

本文包括&#xff1a;30 個 Redis 基礎知識&#xff1b;10個 Redis 架構和運維必懂的知識&#xff1b;Redis 調優、監控知識和10個具體應用難點。 本篇文檔已整理成pdf文檔&#xff0c;需要的同學文末自取 30 個 Redis 基礎知識 1、Redis支持哪幾種數據類型&#xff1f; Str…

【ArcGIS微課1000例】0043:ArcGIS繪制國界線的3種方法

本文講解ArcGIS繪制國界線的3種方法。 文章目錄 1. 直接修改國界線符號2. 緩沖區工具3. 制圖表達1. 直接修改國界線符號 直接修改國界線/省界線的符號。點擊“線要素”出現符號選擇器,點擊【編輯符號】按鈕,編輯成下面右圖的形式。缺點:只能在邊界一側出現緩沖樣式,如下面…

javascript雜記

菜鳥教程   http://www.runoob.com/js/js-tutorial.html 響應鍵盤事件  https://www.cnblogs.com/shihaiming/p/6210655.html 窗口變化  http://www.jb51.net/article/124581.htm div定位1  http://www.divcss5.com/shili/s587.shtml   div定位2  https://www.cnbl…

沒有暑假的Ada 要好好努力咯 C#繼續

嗷嗷嗷啊啊啊啊啊轉載于:https://www.cnblogs.com/AdaLoong/p/5645720.html

C# 獲取系統已安裝的.NET版本

本文經原作者授權以原創方式二次分享&#xff0c;歡迎轉載、分享。原文作者&#xff1a;唐宋元明清原文地址&#xff1a; https://www.cnblogs.com/kybs0/p/16478587.htmlC# 獲取系統已安裝的.NET版本獲取系統已安裝的.NET版本&#xff0c;來確定當前應用可運行的環境。獲取系…

.NET 6 Minimal API 的經驗分享

Minimal API 是 .NET 6 提供的最新功能 &#xff0c; 對比傳統的 ASP.NET Core Web API 方式更加直接 , 你可以用幾行代碼編寫好 REST API 。 沒有了祖傳的 Startup.cs 和 Controller &#xff0c;通過簡單的代碼就可以完成 API 的開發。在第二階段的 .NET 挑戰賽中就以 .NET 6…

JavaWeb之Filter過濾器

原本計劃這一篇來總結JSP&#xff0c;由于JSP的內容比較多&#xff0c;又想著晚上跑跑步減減肥&#xff0c;所以今天先介紹Filter以及它的使用舉例&#xff0c;這樣的話還有些時間可以鍛煉鍛煉。言歸正傳&#xff0c;過濾器從字面理解她的話有攔網、過濾的功能&#xff0c;可以…

【ArcGIS微課1000例】0054:尺寸注記的創建與編輯

尺寸注記要素是一種特殊類型的文本,用于顯示地圖上的長度或距離,可以創建各種形狀的尺寸注記要素,如對齊、簡單對齊、水平線狀、垂直線狀和旋轉線狀等。 文章目錄 一、創建尺寸注記1. 直接創建尺寸注記要素2. 通過已有尺寸注記要素創建二、編輯尺寸注記1. 刪除尺寸注記要素2…

利用python實現批量查詢ip地址歸屬地址

今天需要查詢nginx訪問的客戶端ip是否和調度一樣&#xff01;先是用shell把文件中的ip截取出來&#xff1a; python腳本如下&#xff1a;&#xff08;哈哈&#xff0c;新手寫的很草率&#xff09;#!/usr/bin/env#-- coding: utf-8 - import jsonimport urllibimport socketimpo…

Cobbler部署之FAQ處理

Cobbler報錯處理 通過cobbler check檢查出現的報錯 紅色標注為報錯關鍵信息 9.1 報錯一 # cobbler check httpd does not appear to be running and proxying cobbler, or SELinux is in the way. Original traceback: Traceback (most recent call last): File "/usr…

基于.NetCore開發博客項目 StarBlog - (16) 一些新功能 (監控/統計/配置/初始化)

系列文章基于.NetCore開發博客項目 StarBlog - (1) 為什么需要自己寫一個博客&#xff1f;基于.NetCore開發博客項目 StarBlog - (2) 環境準備和創建項目基于.NetCore開發博客項目 StarBlog - (3) 模型設計基于.NetCore開發博客項目 StarBlog - (4) markdown博客批量導入基于.N…

堪比JMeter的.Net壓測工具 - Crank 入門篇

1. 前言 Crank 是.NET 團隊用來運行基準測試的基準測試基礎架構&#xff0c;包括&#xff08;但不限于&#xff09;來自TechEmpower Web 框架基準測試的場景,是2021年.NET Conf 大會上介紹的一項新的項目&#xff0c;其前身是Benchmarks。 Crank目標之一是為開發人員提供一種工…

【GlobalMapper精品教程】016:按照指定字段批量生成不同用地類型的矢量圖層

Globalmapper中可以很方便的根據指定的字段,對矢量數據進行批量提取,生成不同類型的多個矢量數據,本文以土地利用現狀數據為例,基于DLMC,提取出不同用地類型的矢量圖層。 參考閱讀:【ArcGIS遇上Python】ArcGIS Python按照指定字段批量篩選不同類型的圖斑(以土地利用數據…

javascript閉包—圍觀大神如何解釋閉包

閉包的概念已經出來很長時間了&#xff0c;網上資源一大把&#xff0c;本著拿來主意的方法來看看。 這一篇文章 學習Javascript閉包&#xff08;Closure&#xff09; 是大神阮一峰的博文&#xff0c;作者循序漸進&#xff0c;講的很透徹。下面一一剖析。 1.變量的作用域 變量的…

298. Binary Tree Longest Consecutive Sequence

題目&#xff1a;Given a binary tree, find the length of the longest consecutive sequence path. The path refers to any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The longest consecutive path need to…

Educational Codeforces Round 37 (Rated for Div. 2)

Educational Codeforces Round 37 (Rated for Div. 2) A.Water The Garden 題意&#xff1a;Max想給花園澆水。花園可被視為長度為n的花園床&#xff0c;花園內共有k個水龍頭&#xff0c;分別在花園的xi&#xff08;0≤xi<n&#xff09;處&#xff0c;在j秒內花園的[xi-(j-1…