首頁>科技>

Lambda表示式

Lambda表示式(也稱為閉包)是Java 8中最大和最令人期待的語言改變。它允許我們將函式當成引數傳遞給某個方法,或者把程式碼本身當作資料處理:函式式開發者非常熟悉這些概念。

很多JVM平臺上的語言(Groovy、Scala等)從誕生之日就支援Lambda表示式,但是Java開發者沒有選擇,只能使用匿名內部類代替Lambda表示式。

Lambda的設計耗費了很多時間和很大的社群力量,最終找到一種折中的實現方案,可以實現簡潔而緊湊的語言結構。而lambda表示式的使用需要和函式式介面結合。

1.函式式介面

1.1.概念

函式式介面在Java中是指:有且僅有一個抽象方法的介面。 函式式介面,即適用於函數語言程式設計場景的介面。而Java中的函數語言程式設計體現就是Lambda,所以函式式介面就是可 以適用於Lambda使用的介面。只有確保介面中有且僅有一個抽象方法,Java中的Lambda才能順利地進行推導。 備註:“語法糖”是指使用更加方便,但是原理不變的程式碼語法。例如在遍歷集合時使用的for-each語法,其實 底層的實現原理仍然是迭代器,這便是“語法糖”。從應用層面來講,Java中的Lambda可以被當做是匿名內部 類的“語法糖”,但是二者在原理上是不同的。

1.2,格式

只要確保介面中有且僅有一個抽象方法即可:

1. 修飾符 interface 介面名稱 {

2. public abstract 返回值型別 方法名稱(可選引數資訊);

3. }

1.3 @FunctionalInterface註解

與 @Override 註解的作用類似,Java 8中專門為函式式介面引入了一個新的註解: @FunctionalInterface 。該註解可用於一個介面的定義上:

1. @FunctionalInterface

2. public interface MyFunctionalInterface {

3. void myMethod();

4. }

一旦使用該註解來定義介面,編譯器將會強制檢查該介面是否確實有且僅有一個抽象方法,否則將會報錯。需要注 意的是,即使不使用該註解,只要滿足函式式介面的定義,這仍然是一個函式式介面,使用起來都一樣.

2.函式式介面的使用

2.1函式式介面作為引數,方法不帶引數

1. //定義函式式介面

2. public interface MyInterface{

3.

4. public abstract void show();

5.

6. }

7.

8. //使用(匿名內部類物件/函式式)

9. public class Demo01 {

10.

11. public static void main(String[] args) {

12. method01(new MyInterface01() {

13.

14. @Override

15. public void show() {

16. System.out.println("你好,函式式介面");

17. }

18. });

19. // 函式式

20. method01(() -> {

21. System.out.println("你好,函式式介面");

22. });

23. // 函式式簡寫(如果方法體中只有一句程式碼)

24. method01(() -> System.out.println("你好,函式式介面"));

25. }

26.

27. public static void method01(MyInterface01 inter) {

28. inter.show();

29. }

30.

31. }

函式式介面的優勢

函式式介面比匿名內部類物件產生更少的位元組碼物件,提升java執行效率.

2.2, 函式式介面作為引數,方法帶引數

1. //定義函式式介面

2. public interface MyInterface02 {

3.

4. public abstract void show(String msg1, String msg2);

5.

6. }

7.

8. //使用函式式介面

9. public static void main(String[] args) {

10. //匿名內部類物件

11. method01(new MyInterface02() {

12.

13. @Override

14. public void show(String msg1, String msg2) {

15. System.out.println(msg1 + msg2);

16. }

17. });

18. //函式式完整

19. method01((String msg1, String msg2) -> {

20. System.out.println(msg1 + msg2);

21. });

22. //函式式簡寫

23. method01((msg1, msg2) -> System.out.println(msg1 + msg2));

24.

25. }

26.

27. public static void method01(MyInterface02 inter) {

28. inter.show("hello", "函式式");

29. }

2.3, 函式式介面作為返回值,方法不帶引數

1. //定義函式式介面

2. public interface MyInterface02 {

3.

4. public abstract void show(String msg1, String msg2);

5.

6. }

7. public static void main(String[] args) {

8.

9. getInter1().show("你好", "函式式");

10. getInter2().show("你好", "函式式");

11.

12. }

13.

14. // 函式式完整

15. public static MyInterface02 getInter1() {

16.

17. return (String msg1, String msg2) -> {

18. System.out.println(msg1 + msg2);

19. };

20. }

21.

22. // 函式式簡寫

23. public static MyInterface02 getInter2() {

24.

25. return (msg1, msg2) -> System.out.println(msg1 + msg2);

26. }

3.函數語言程式設計應用場景

3.1,概念

在兼顧面向物件特性的基礎上,Java語言通過Lambda表示式使用函式式介面,就叫做函數語言程式設計

3.2, 使用lambada作為引數

如果拋開實現原理不說,Java中的Lambda表示式可以被當作是匿名內部類的替代品。如果方法的引數是一個函式 式介面型別,那麼就可以使用Lambda表示式進行替代。

1. public class Demo04Runnable{

2. private static void startThread(Runnable task){

3. new Thread(task).start();

4. }

5. public static void main(String[] args) {

6. startThread(()‐>System.out.println("執行緒執行"));

7. }

8. }

3.3, 使用函式式介面作為返回值

如果一個方法的返回值型別是一個函式式介面,那麼就可以直接返回一個Lambda表示式。

1. public class Demo06Comparator {

2.

3. private static Comparator<Integer> getComparator(){

4. return (num1,num2)‐> num1 - num2;

5. }

6.

7. public static void main(String[] args) {

8. Integer[] array = {3,2,1};

9. Arrays.sort(array, getComparator());

10. //遍歷陣列

11. }

12. }

3.4, 函式式介面的方法有返回值

1. public static void main(String[] args) {

2.

3. showMsg(new MyInterface03() {

4.

5. @Override

6. public String getMsg() {

7. return "hello functional interface";

8. }

9. });

10.

11. // lambada表示式

12. showMsg(() -> {

13.

14. return "hello1 functional interface";

15. });

16.

17. // lambda表示式簡寫

18. showMsg(() -> "hello1 functional interface");

19.

20. }

21.

22. public static void showMsg(MyInterface03 inter) {

23. String msg = inter.getMsg();

24. System.out.println(msg);

25. }

4.常用函式式介面(Supplier介面)

JDK提供了大量常用的函式式介面以豐富Lambda的典型使用場景,它們主要在 java.util.function 包中被提供。 下面是簡單的幾個介面及使用示例。

4.1,Supplier介面

java.util.function.Supplier<T> 介面僅包含一個無參的方法: T get() 。用來獲取一個泛型引數指定型別的物件資料。由於這是一個函式式介面,這也就意味著對應的Lambda表示式需要“對外提供”一個符合泛型型別的物件資料

4.2,基本使用

1. private static String getString(Supplier<String> function ){

2. return function.get();

3. }

4. public static void main(String[] args){

5. String msgA="Hello";

6. String msgB="World";

7. System.out.println(getString(()->msgA+msgB));

8. }

4.2,綜合案例

需求:使用 Supplier 介面作為方法引數型別,通過Lambda表示式求出int陣列中的最大值。提示:介面的泛型請使用 java.lang.Integer 類。

1. public static void main(String[] args) {

2. Integer max = getMax(()->{

3. Integer[] nums = {1,2,3,4};

4. int max2 = nums[0];

5. for (Integer num : nums) {

6. if(max2 < num){

7. max2 = num;

8. }

9. }

10. return max2;

11. });

12. System.out.println(max);

13. }

14.

15. public static Integer getMax(Supplier<Integer> supplier){

16. return supplier.get();

17. }

5.常用函式式介面(Consumer介面)

5.1,Consumer介面

java.util.function.Consumer<T> 介面則正好與Supplier介面相反,它不是生產一個數據,而是消費一個數據, 其資料型別由泛型決定

5.2,accept方法

Consumer 介面中包含抽象方法 void accept(T t) ,意為消費一個指定泛型的資料。基本使用如:

1. public static void main(String[] args) {

2. consumeString((msg)->System.out.println(msg));

3. }

4.

5.

6. public static void consumeString(Consumer<String> consumer){

7. consumer.accept("hello");

8. }

5.3, andThen方法

如果一個方法的引數和返回值全都是 Consumer 型別,那麼就可以實現效果:消費資料的時候,首先做一個操作, 然後再做一個操作,實現組合。而這個方法就是 Consumer 介面中的default方法 andThen

1. default Consumer<T> andThen(Consumer<? super T> after) {

2. Objects.requireNonNull(after);

3. return (T t) -> { accept(t); after.accept(t); };

4. }

注: java.util.Objects 的 requireNonNull 靜態方法將會在引數為null時主動丟擲 NullPointerException 異常。這省去了重複編寫if語句和丟擲空指標異常的麻煩。

需求:先列印大寫HELLO,再列印小寫hello

1. public static void main(String[] args) {

2. consumeString((msg) -> System.out.println(msg.toUpperCase()),

3. (msg) -> System.out.println(msg.toLowerCase()));

4. }

5.

6. public static void consumeString(Consumer<String> consumer1, Consumer<String> consumer2) {

7. consumer1.andThen(consumer2).accept("hello");

8. }

6.常用函式式介面(Predicate介面)

有時候我們需要對某種型別的資料進行判斷,從而得到一個boolean值結果。這時可以使用 java.util.function.Predicate<T> 介面

6.1, test方法

Predicate 介面中包含一個抽象方法: boolean test(T t) 。用於條件判斷的場景

1. public enum SingleClass06 {

2. INSTANCE;

3. }

6.2,基本使用

1. public static void main(String[] args) {

2. System.out.println(predicateTest((msg) -> msg.length() > 3, "hello"));

3. }

4.

5.

6. public static boolean predicateTest(Predicate<String> predicate,String msg){

7. return predicate.test(msg);

8.

9. }

7.總結

在本文中,我們學會了使用lambda表示式的不同方式,同時也學習了java8.0開始自帶的一些常用函式式介面。

  • 整治雙十一購物亂象,國家再次出手!該跟這些套路說再見了
  • Facebook研發AI面部識別欺騙系統