程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> Java 8 Lambda表達式,讓你的代碼更簡潔,lambda表達式

Java 8 Lambda表達式,讓你的代碼更簡潔,lambda表達式

編輯:JAVA綜合教程

Java 8 Lambda表達式,讓你的代碼更簡潔,lambda表達式


Lambda表達式是Java 8一個非常重要的新特性。它像方法一樣,利用很簡單的語法來定義參數列表和方法體。目前Lambda表達式已經成為高級編程語言的標配,像Python,Swift等都已經支持Lambda表達式。

在Java 8的實現中,Lambda表達式其本質只是一個“語法糖”,經過編譯器推斷和處理,將其轉換包裝為常規的Java代碼,因此就像題目所寫的那樣,可以讓你的代碼更為簡潔。

Lambda表達式的基本語法:(parameters) -> expression 或 (parameters) -> { statements; }

Lambda表達式並不是一個方法,它可以用來定義了一個代碼塊,形式上很像是Java的匿名內部類。Lambda表達式通常會賦值給一個函數式接口,函數式接口是指只有一個抽象方法的接口。Lambda表達式可以通過上下文環境來推斷變量類型, 因此在使用時盡量不人為明確的指定變量類型。

舉例來看,假設我們有一個List<String>類型的列表list,如果要遍歷並打印列表內容,Java 7以前的代碼如下:

1 for (String s : list) {
2     System.out.println(s);
3 }

 

Java 8來實現的話:

1 list.forEach((s) -> System.out.println(s));

或者

1 list.forEach(System.out::println);

再看一個例子,假設我們要對list進行排序,Java 7的代碼如下:

1 Collections.sort(list, new Comparator<String>() {
2     @Override
3     public int compare(String p1, String p2) {
4         return p1.compareTo(p2);
5     }
6 });

Java 8來實現的話:

1 Collections.sort(list, (String p1, String p2) -> p1.compareTo(p2));

需要注意的是,Lambda表達式可以做參數類型推斷,這裡我們可以充分利用這一點,p1和p2參數前面的String是不需要的,因此可以簡化一步如下:

1 Collections.sort(list, (p1,p2) -> p1.compareTo(p2));

更進一步:

1 list.sort((p1,p2) -> p1.compareTo(p2));

是不是簡潔了很多:)

Lambda表達式也可以用來代替匿名類。例如我們要實現Runnable接口,Java 7的代碼如下:

1 new Thread(new Runnable() {
2     @Override
3     public void run() {
4         System.out.println("Hello world !");
5     }
6 }).start();

 

Java 8來實現的話:

1 new Thread(() -> System.out.println("Hello world !")).start();

用Lambda表達式來實現Runnable,將五行代碼轉換成一行語句。

合理使用Lambda表達式,不僅能簡化幾行代碼,還能做到合理的代碼抽象。當我們在實現的兩個很大的方法時,如果大部分的代碼都是相同的,只有一小點代碼不一樣時,我們可以通過將Lambda表達式作為參數傳入,以達到不同表意的目的。

前面提到的函數式接口(Functional Interfaces),它表示只有一個抽象方法的接口,可以用來指向Lambda表達式。例如:

1 Consumer c = (s) -> System.out.println(s);

Java 8在java.util.function包中實現了新的幾個:

  • Function<T, R>:接受一個參數T,返回結果R

  • Predicate<T>:接受一個參數T,返回boolean

  • Supplier<T>:不接受任何參數,返回結果T

  • Consumer<T>:接受一個參數T,不返回結果

  • UnaryOperator<T>:繼承自Function<T, T>,接受一個參數T,返回相同類型T的結果

  • BiFunction<T, U, R>:接受兩個參數T和U,返回結果R

  • BinaryOperator<T>:繼承自BiFunction<T, T, T>,接受兩個相同類型T的參數,返回相同類型T的結果

  • ……

另外,我們最為熟悉的函數式接口還有:

  • Runnable:實際上是不接受任何參數,也不返回結果

  • Comparable<T>:實際上是接受兩個相同類型T的參數,返回int

  • Callable<V>:不接受任何參數,返回結果V

通常我們應該盡量使用標准的函數式接口,如果我們要自定義的話,可以使用@FunctionalInterface注解,例如:

1 @FunctionalInterface
2 public interface funcInterface {
3     public abstract B op(A a);
4 }

 

在將函數式接口作為參數時,需要注意盡量避免方法重載。由於Lambda表達式根據所在環境的目標類型來決定Lambda表達式的類型(也就是Target Typing), 因此方法重載有時會導致編譯器犯暈。我們可以使用不同的方法名來解決這個問題。

在這裡,我們還需要澄清幾點:

  • Lambda表達式並不是函數式接口。它能賦值給函數式接口,是因為編譯器將它包裝成了對應的函數式接口;

  • 更進一步,Lambda表達式也不是匿名類:

    • 它並沒有定義新的作用域,外面定義的局部變量在Lambda表達式內部是可見的;

    • 它不能改變外部變量的值,只能讀取final或者effectively final的變量;

    • 它不能前向讀取外部變量,也就是只有在外部變量申明之後才能讀取,而在匿名內部類是可以的;

Java 8 還增強了對集合數據的批量操作Stream,通常會和Lambda表達式一起使用。Lambda表達式和 Stream 可以說是Java語言從添加泛型(Generics)和注解(annotation)以來最大的變化了。下一篇文章將重點介紹Stream。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved