中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

不知道面試會不會問Lambda怎么用(推薦)

發布時間:2020-09-16 02:10:19 來源:腳本之家 閱讀:168 作者:邊緣煩惱 欄目:編程語言

我們先假設一個場景想象一下,當一個項目出現bug的時候,恰巧這個時候需要你去修改,而當你打開項目之后,眼前的代碼讓你有一種特別嚴重的陌生感,你會不會慌?心里是不是瞬間就會噴涌而出各種想法:我這是打開的啥語言的項目?還是我眼花看錯了?難道是我過時了?這寫的是個啥子玩意兒…

java8在14年就出來了,已經很久了,但是還是有很多人沒用過,包括我之前的同事都對這個不太熟悉,原因可能是多樣的,可能是老程序員覺得沒必要;也可能是性格使然,拒絕接受新的東西,一切守舊,能用就行;也可能是項目太老了,還在用JDK1.7,或者更老的版本,平時根本就接觸不到java8的寫法,也不需要去接觸。

無論是什么原因,在新事物出現之后,沒有一股探險精神,不去嘗試,不去結合自己的處境去思考,這樣下去就算天上掉餡餅也輪不到你啊。

這篇短文說下Lambda表達式,有一定的編程基礎的小伙伴簡單看下應該就會明白,不僅僅寫著舒服,更能提供你的工作效率,讓你有更多的時間帶薪劃水,自我提高,走向人生巔峰。

Lambda表達式

Lambda表達式可以理解為一種匿名函數:沒有名稱、有參數列表、函數主體、返回類型,可能還會有異常的列表。

參數 -> 主體

lambda表達式:(parameters) -> expression 或者是 (parameters) -> { statements; }

函數式接口

什么是函數式接口?

僅僅定義了一個抽象方法的接口,類似于Predicate、Comparator和Runnable。

@FunctionalInterface 函數式接口都帶有這個注解,這個注解表示這個接口會被設計為函數式接口。

行為參數化

一個方法接受多個不同的行為作為參數,并在內部使用它們,完成不同行為的能力。

函數式接口可以做些什么?

Lambda表達式允許你直接以內聯的形式為函數式接口的抽象方法提供實現,并且把整個表達式作為函數式接口的實例,也就是說,Lambda是函數式接口的一個具體實現。函數式接口和Lambda會在項目中寫出更加簡潔易懂的代碼。

接下來我們看下幾種函數式接口:

  1. java.util.function.Predicate:這個接口中定義了一個test的抽象方法,它接受泛型T對象,并返回一個boolean值,在你需要表示一個涉及類型T的布爾表達式時,就可以使用這個接口。
  2. java.util.function.Consumer:這個接口中定義了accept抽象方法,它接受泛型T的對象,沒有返回。如果你需要訪問類型T的對象,并執行某些操作,可以用它。
  3. java.util.function.Function:這個接口定義了一個apply的方法,它接受一個泛型T的對象,并返回一個泛型R的對象,如果你需要定一個Lambda,將輸入對象的信息映射到輸出對象,就可以使用這個接口。
  4. ps:我們也可以自己定義一個自己需要的函數式接口。

這么說實在是太生澀了,還是貼點代碼,讓大家都看看:

@FunctionalInterface
public interface Predicate<T> {
 //我只截取了部分代碼,test是這個接口唯一的抽象方法,話說從java8開始,接口中不僅 
 //僅只能有抽象方法了,實現的方法也可以存在,用default和static來修飾。
 boolean test(T t);
 default Predicate<T> and(Predicate<? super T> other) {
  Objects.requireNonNull(other);
  return (t) -> test(t) && other.test(t);
 }

。

接下來,看下Lambda和函數式接口是怎么配合,一起快樂的工作的: 首先定義一個方法,這個方法的參數中有函數式接口:

private static <T> List<T> filter(List<T> list, Predicate<T> predicate) {
 List<T> result = new ArrayList<>();
 for (T e : list) {
  if (predicate.test(e)) {
   result.add(e);
  }
 }
 return result;
}

接下來你就可以這么寫:

List<Apple> apples = filter(list, (Apple apple) -> "red".equals(apple.getColor()));

以上,filter方法的參數是一個泛型集合和Predicate,這個函數式接口中的抽象方法是接受一個對象并返回一個布爾值,所以Lambda我們可以寫成參數是一個實體對象Apple,主體是一個返回boolean值的表達式,將這段Lambda作為參數傳給filter()方法,這也是java8的行為參數化特性。以上我們就可以挑選出紅蘋果。

使用了泛型,就代表著我們還可以復用這段代碼做些別的事情,挑選出你想要東東的:

List<String> stringList = filter(strList, StringUtils::isNoneBlank);

抽象方法的方法簽名和Lambda表達式的簽名是一一對應的,如果你要應用不同的Lambda表達式,就需要多個函數式接口,當然了我也是可以自己定義的。

在java中只有引用類型或者是原始類型,這是由泛型內部的實現方式造成的。因此,在Java里有一個將原始類型轉換為對應的引用類型的機制,這個機制叫作裝箱(boxing)。相反的操作,也就是將引用類型轉換為對應的原始類型,叫作拆箱(unboxing)。

Java還有一個自動裝箱機制,也就是說裝箱和拆箱操作是自動完成的,但這在性能方面是要付出代價的。裝箱后的值本質上就是把原始類型包裹起來,并保存在堆里。因此,裝箱后的值需要更多的內存,并需要額外的內存來搜索獲取被包裹的原始值。

針對于這一點,java8中的函數式接口提供了單獨的接口,就是為了在輸入和輸出的時候避免自動裝箱拆箱的操作,是不是很貼心。

一般情況下,在名稱上我們就能看得出來,一目了然。在原來的名稱上會有原始類型前綴。像Function接口針對輸出參數類型的變形。比如說:ToIntFunction、IntToDoubleFunction等。

在必要的情況下,我們也可以自己定義一個函數式接口,請記住,(T,U) -> R的表達方式展示了對一個函數的簡單描述,箭頭的的左側代表了參數類型,右側代表著返回類型,這里它代表一個函數,具有兩個參數,分別為泛型T和U,返回類型為R。

函數式接口是不允許拋出 受檢異常(checked exception),但是有兩個方法可以拋出異常:

  1. 定義一個自己的函數式接口,在唯一的抽象方法拋出異常;
  2. 用try-catch 將lambda 包起來。

類型檢查

java7是通過泛型從上下文推斷類型,lambda的類型檢查是通過它的上下文推斷出來的。lambda會找到它所在的方法的方法簽名,也就是它的參數,也就是他們說的目標類型,再找到這個方法中定義的抽象方法,這個方法描述的函數描述符是什么?也就是這個方法是個什么樣的,接受什么參數,返回什么。lambda也必須是符合這樣的。當lambda拋出異常的時候,那個抽象方法也必須要拋出異常。
有了目標類型,那么同一個lambda就可以與不同的函數式接口聯系起來。只要他們的抽象方法簽名是一樣的。
例如:

Callable<Integer> c = () -> 42;
PrivilegedAction<Integer> p = () -> 42;

這兩個接口都是沒有參數,且返回一個泛型T的函數。 void兼容規則 lambda的主題是一個語句表達式,和一個返回void的函數描述符兼容,包括參數列表, 比如下面:

// Predicate返回了一個boolean
Predicate<String> p = s -> list.add(s);
// Consumer返回了一個void
Consumer<String> b = s -> list.add(s);

在lambda中使用局部變量

final int local_value = 44;
Consumer<String> stringConsumer = (String s) -> {
   int new_local_value = s.length() + local_value;
  };

在lambda中可以無限制的使用實例變量和靜態變量,但是只能是final的,如果在表達式里面給變量賦值,就會編譯不通過。為什么會有這樣的呢?

因為實例變量存儲在堆中,局部變量存儲在棧中,lambda是在一個線程中,如果lambda可以直接訪問局部變量,lambda的線程可能會在分配該變量的線程將這個變量回收之后,再去訪問該變量。在訪問局部變量的時候,實際上是訪問他的副本,而不是原始變量。

方法引用

方法引用,方法目標實體放在::的前面,方法名放在后面。比如 Apple::getWeight,不需要括號。

構造函數是可以利用它的名稱和關鍵字 new來創建一個引用。

//Supplier也是一個函數式接口,唯一的抽象方法不接受參數,直接返回一個對象
Supplier<Apple> sup = Apple::new;
  Apple apple = sup.get();

但是如果是有參數的呢?

//一個參數
Function<Long, Apple> fun = Apple::new;
    Apple apple1 = fun.apply(110L);
//兩個參數
 BiFunction<Long, String, Apple> biFunction = Apple::new;
 Apple biApple = biFunction.apply(3L, "red");

但是如果有三個參數、四個參數呢?我們上面說了怎么樣可以自定義一個自己需要的函數式接口。

@FunctionalInterface
public interface AppleWithParam<T, U, V, R> {
  R apply(T t, U u, V v);
}

總結:

  1. java8中自帶的函數式接口,以及為了避免拆裝箱操作而產生的函數式接口的原始類型轉化。
  2. 函數式接口就是僅僅定義一個抽象方法的接口。抽象方法的簽名(稱為函數描述符) 描述了Lambda表達式的簽名。
  3. 只有在接受函數式接口的地方才可以使用Lambda表達式。
  4. 接口現在還可以擁有默認方法,(就是類沒有對方法進行實現的時候,它實現的接口來提供默認實現的方法)

以上所述是小編給大家介紹的Lambda表達式詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對億速云網站的支持!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

常宁市| 麻阳| 梅河口市| 托克托县| 广河县| 化德县| 湘乡市| 黄冈市| 莎车县| 马公市| 潞城市| 景泰县| 石渠县| 旌德县| 黑龙江省| 宝应县| 当涂县| 辽阳市| 武川县| 玛多县| 潞西市| 江山市| 谢通门县| 安达市| 崇义县| 习水县| 错那县| 繁峙县| 克东县| 阿拉善右旗| 利辛县| 凉城县| 巍山| 施甸县| 五指山市| 新田县| 连江县| 刚察县| 襄城县| 离岛区| 广德县|