摘要:表達(dá)式會(huì)復(fù)制一份自由變量的值,對(duì)象的話就是復(fù)制一個(gè)引用,因此表達(dá)式離開了原作用域也能正常使用自由變量。不過表達(dá)式對(duì)自由變量是有要求的,自由變量必須是不可變的,原因是并發(fā)執(zhí)行時(shí)不安全。
序
Java 8新增的lambda表達(dá)式毫無疑問是令人非常激動(dòng)的,從此我們可以非常簡(jiǎn)潔的定義和使用代碼塊而不是用繁瑣的匿名內(nèi)部類來實(shí)現(xiàn)。而接口是lambda表達(dá)式的基礎(chǔ),要理解lambda表達(dá)式就要先理解接口的概念。
接口在Java中接口是對(duì)類行為的抽象。似乎繼承也能做到這件事,它們的區(qū)別在于Java中類只能有一個(gè)父類,而接口是可以實(shí)現(xiàn)多個(gè)的。所以接口更傾向于類的一部分抽象,也就是行為的抽象,而不是類本身的抽象。
語法要定義一個(gè)接口很簡(jiǎn)單,使用關(guān)鍵字interface后面再跟上接口名稱就可以了。類可以用implements關(guān)鍵字來實(shí)現(xiàn)接口。
public interface A { void test(); }
接口不允許有實(shí)例域,但可以有常量
接口中的域都會(huì)自動(dòng)聲明為public static final
接口中的方法都會(huì)自動(dòng)聲明為public
接口中可以聲明抽象方法,Java 8以后還可以聲明靜態(tài)方法和默認(rèn)方法
// Java 8版本 public interface A { //常量 String AUTHOR = "Yuicon"; //抽象方法 void test(); //默認(rèn)方法 default void testDefault(){} //靜態(tài)方法 static void testStatic(){} }默認(rèn)方法的沖突
如果一個(gè)類實(shí)現(xiàn)的接口中有簽名相同的默認(rèn)方法,那么就會(huì)有沖突的問題。在Java中解決這個(gè)問題有一些明確的規(guī)則:
在超類中已有同簽名的方法,就會(huì)忽略接口中的默認(rèn)方法,也就是超類優(yōu)先
接口中默認(rèn)方法和另一個(gè)默認(rèn)方法或者抽象方法沖突的,必須要覆蓋這個(gè)方法
lambda表達(dá)式lambda表達(dá)式是一個(gè)可傳遞的代碼塊,可以在以后執(zhí)行一次或多次。之所以會(huì)有這么一個(gè)特性,是因?yàn)樵仍贘ava中傳遞一個(gè)代碼塊是非常繁瑣的一件事情,必須要構(gòu)建一個(gè)對(duì)象。比如常用的Runnable接口:
Runnable runnable = new Runnable() { @Override public void run() { System.out.println("我好麻煩"); } };
lambda版本就非常簡(jiǎn)潔:
Runnable runnable = () -> System.out.println("我很簡(jiǎn)潔");
是的,lambda版本只要一行就完成了任務(wù)。
語法在我看來lambda表達(dá)式是一種語法糖,它提供了一種簡(jiǎn)潔、易懂的方式來實(shí)現(xiàn)只有一個(gè)抽象方法的接口。關(guān)鍵詞是只有一個(gè)抽象方法的接口,比如這樣一個(gè)接口:
@FunctionalInterface public interface A { void test(); } A a = () -> System.out.println("test"); a.test();
其中@FunctionalInterface注解是用來標(biāo)記接口為函數(shù)式接口,去掉也不會(huì)影響功能,添加了這個(gè)注解后編譯器會(huì)檢查接口內(nèi)是否只有一個(gè)抽象方法。
lambda表達(dá)式主要有以下要素:
參數(shù)
箭頭 ->
方法體
自由變量
參數(shù)lambda表達(dá)式的參數(shù)和普通方法的參數(shù)并無太大區(qū)別,主要的區(qū)別點(diǎn)有:
如果參數(shù)的類型可以被編譯器推導(dǎo)出來,那么可以省略參數(shù)類型
如果參數(shù)的類型可以被編譯器推導(dǎo)出來,而且只有一個(gè)參數(shù),那么就可以省略括號(hào)
Consumer方法體consumer = s -> System.out.println(s);
lambda表達(dá)式的方法體內(nèi)只有一條語句的時(shí)候,可以不加大括號(hào)且無需指定返回值,編譯器會(huì)自動(dòng)推導(dǎo)。方法體內(nèi)有多條語句的時(shí)候就需要加大括號(hào)并手動(dòng)指定返回值,不過lambda表達(dá)式是沒有自己的作用域的,這點(diǎn)需要注意。
Supplier自由變量supplier = () -> { String s = "test"; return s; };
自由變量是指非參數(shù)而且不在方法體內(nèi)定義的變量,我們來看一個(gè)例子:
public static void main(String[] args) { String test = "test"; A a = () -> System.out.println(test); a.test(); }
例子中的變量test就是一個(gè)自由變量,代碼塊a引用了外部方法的變量,這就是一個(gè)閉包了。lambda表達(dá)式會(huì)復(fù)制一份自由變量的值,對(duì)象的話就是復(fù)制一個(gè)引用,因此lambda表達(dá)式離開了原作用域也能正常使用自由變量。不過lambda表達(dá)式對(duì)自由變量是有要求的,自由變量必須是不可變的,原因是并發(fā)執(zhí)行時(shí)不安全。以下代碼是錯(cuò)誤的:
for (int i = 0; i < 9; i++) { // error A a = () -> System.out.println(i); }方法引用
方法引用是語法糖的語法糖,顧名思義方法引用是引用已有方法的一個(gè)特性。它的形式如下:
@FunctionalInterface public interface A { void test(String s); } A a = System.out::println; a.test("test");
之所以說方法引用是語法糖的語法糖是因?yàn)?b>A a = System.out::println;完全等價(jià)于A a = s -> System.out.println(s);,方法引用有5種情況:
object::instanceMethod
this::instanceMethod
super::instanceMethod // 超類方法
Class::staticMethod
Class::instanceMethod
前4種情況和lambda表達(dá)式是完全等價(jià)的,第5種情況比較特殊,第一個(gè)參數(shù)會(huì)成為方法的目標(biāo)。比如String::compareToIgnoreCase等同于 (x, y)-> x.compareToIgnoreCase(y)。
構(gòu)造器引用構(gòu)造器引用是引用對(duì)象的構(gòu)造器,用的是特殊的方法名new,使用形式為Object::new,使用方法和方法引用差不多。
常用函數(shù)式接口JDK已經(jīng)提供了常用的函數(shù)式接口基本上是不需要自己寫函數(shù)式接口的。
后記一周一篇是不可能一周一篇的,人懶起來就和咸魚一樣根本不會(huì)動(dòng)彈。還好人是會(huì)變通的,上周少了這周補(bǔ)上不就行了!Java被人詬病繁瑣不是一天兩天了,在各種新生編程語言的追趕下Java也要加快自己的演進(jìn)了,更改發(fā)布周期就是一個(gè)很好的信號(hào)。
參考資料:
《Java核心技術(shù) 卷1》
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/76841.html
摘要:即接口是用來描述對(duì)象具有的某種功能,而不關(guān)心具體實(shí)現(xiàn)?;蛘哒f,接口好比服務(wù)商指定的標(biāo)準(zhǔn),由代加工工廠遵守來生產(chǎn)。內(nèi)部類允許在類中定義其它類,這種定義在類中的類叫做嵌套類。局部類是聲明,匿名類是表達(dá)式。匿名類當(dāng)需要聲明字段或其它方法時(shí)。 接口 在繼承那篇博文里,我們已經(jīng)簡(jiǎn)單了解了 Java 接口的概念。即:接口是用來描述對(duì)象具有的某種「功能」,而不關(guān)心具體實(shí)現(xiàn)?;蛘哒f,接口好比服務(wù)商指定...
摘要:新特性總覽標(biāo)簽本文主要介紹的新特性,包括表達(dá)式方法引用流默認(rèn)方法組合式異步編程新的時(shí)間,等等各個(gè)方面。還有對(duì)應(yīng)的和類型的函數(shù)連接字符串廣義的歸約匯總起始值,映射方法,二元結(jié)合二元結(jié)合。使用并行流時(shí)要注意避免共享可變狀態(tài)。 Java8新特性總覽 標(biāo)簽: java [TOC] 本文主要介紹 Java 8 的新特性,包括 Lambda 表達(dá)式、方法引用、流(Stream API)、默認(rèn)方...
摘要:在支持一類函數(shù)的語言中,表達(dá)式的類型將是函數(shù)。匿名函數(shù)的返回類型與該主體表達(dá)式一致如果表達(dá)式的主體包含一條以上語句,則表達(dá)式必須包含在花括號(hào)中形成代碼塊。注意,使用表達(dá)式的方法不止一種。 摘要:此篇文章主要介紹 Java8 Lambda 表達(dá)式產(chǎn)生的背景和用法,以及 Lambda 表達(dá)式與匿名類的不同等。本文系 OneAPM 工程師編譯整理。 Java 是一流的面向?qū)ο笳Z言,除了部分簡(jiǎn)...
摘要:概述簡(jiǎn)介是一個(gè)匿名函數(shù),我們可以把表達(dá)式理解為是一段可以傳遞的代碼將代碼像數(shù)據(jù)一樣進(jìn)行傳遞。作為一種更緊湊的代碼風(fēng)格,使的語言表達(dá)能力得到了提升。任何滿足單一抽象方法法則的接口,都會(huì)被自動(dòng)視為函數(shù)接口。 1. 概述 1.1 簡(jiǎn)介 Lambda 是一個(gè)匿名函數(shù),我們可以把 Lambda 表達(dá)式理解為是一段可以傳遞的代碼(將代碼像數(shù)據(jù)一樣進(jìn)行傳遞)。可以寫出更簡(jiǎn)潔、更靈活的代碼。作為一種更...
摘要:編程語言將函數(shù)作為一等公民,函數(shù)可以被作為參數(shù)或者返回值傳遞,因?yàn)樗灰暈閷?duì)象。是表示已注釋接口是函數(shù)接口的注釋。如果一個(gè)函數(shù)有一個(gè)或多個(gè)參數(shù)并且有返回值呢為了解決這個(gè)問題,提供了一系列通用函數(shù)接口,在包里。 【編者按】雖然 Java 深得大量開發(fā)者喜愛,但是對(duì)比其他現(xiàn)代編程語言,其語法確實(shí)略顯冗長(zhǎng)。但是通過 Java8,直接利用 lambda 表達(dá)式就能編寫出既可讀又簡(jiǎn)潔的代碼。作者...
閱讀 727·2021-11-22 13:52
閱讀 1537·2021-09-27 13:36
閱讀 2840·2021-09-24 09:47
閱讀 2199·2021-09-22 15:48
閱讀 3612·2021-09-22 15:39
閱讀 1478·2019-08-30 12:43
閱讀 2930·2019-08-29 18:39
閱讀 3201·2019-08-29 12:51