亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java Lambda 表達式詳解及示例代碼

 更新時間:2016年09月08日 08:50:52   作者:不爭  
本文主要介紹Java Lambda 表達式的知識,這里整理了相關資料,JavaLambda 是Java8 引入的新功能,有興趣的小伙伴可以參考下

Java Lambda 表達式是 Java 8 引入的一個新的功能,可以說是模擬函數(shù)式編程的一個語法糖,類似于 Javascript 中的閉包,但又有些不同,主要目的是提供一個函數(shù)化的語法來簡化我們的編碼。

Lambda 基本語法

Lambda 的基本結構為 (arguments) -> body,有如下幾種情況:

  1. 參數(shù)類型可推導時,不需要指定類型,如 (a) -> System.out.println(a)
  2. 當只有一個參數(shù)且類型可推導時,不強制寫 (), 如 a -> System.out.println(a)
  3. 參數(shù)指定類型時,必須有括號,如 (int a) -> System.out.println(a)
  4. 參數(shù)可以為空,如 () -> System.out.println(“hello”)

body 需要用 {} 包含語句,當只有一條語句時 {} 可省略

常見的寫法如下:

(a) -> a * a
(int a, int b) -> a + b
(a, b) -> {return a - b;}
() -> System.out.println(Thread.currentThread().getId())

函數(shù)式接口 FunctionalInterface

概念

Java Lambda 表達式以函數(shù)式接口為基礎。什么是函數(shù)式接口(FunctionalInterface)? 簡單說來就是只有一個方法(函數(shù))的接口,這類接口的目的是為了一個單一的操作,也就相當于一個單一的函數(shù)了。常見的接口如:Runnable, Comparator 都是函數(shù)式接口,并且都標注了注解 @FunctionalInterface 。

舉例

以 Thread 為例說明很容易理解。Runnable 接口是我們線程編程時常用的一個接口,就包含一個方法 void run(),這個方法就是線程的運行邏輯。按照以前的語法,我們新建線程一般要用到 Runnable 的匿名類,如下:

new Thread(new Runnable() {
  @Override
  public void run() {
    System.out.println(Thread.currentThread().getId());
  }

}).start();

如果寫多了,是不是很無聊,而基于 Lambda 的寫法則變得簡潔明了,如下:

new Thread(() -> System.out.println(Thread.currentThread().getId())).start();

注意 Thread 的參數(shù),Runnable 的匿名實現(xiàn)就通過一句就實現(xiàn)了出來,寫成下面的更好理解

Runnable r = () -> System.out.println(Thread.currentThread().getId());
new Thread(r).start();

當然 Lambda 的目的不僅僅是寫起來簡潔,更高層次的目的等體會到了再總結。

再看一個比較器的例子,按照傳統(tǒng)的寫法,如下:

Integer[] a = {1, 8, 3, 9, 2, 0, 5};
Arrays.sort(a, new Comparator<Integer>() {
  @Override
  public int compare(Integer o1, Integer o2) {
    return o1 - o2;
  }
});

Lambda 表達式寫法如下:

Integer[] a = {1, 8, 3, 9, 2, 0, 5};
Arrays.sort(a, (o1, o2) -> o1 - o2);

JDK中的函數(shù)式接口

為了現(xiàn)有的類庫能夠直接使用 Lambda 表達式,Java 8 以前存在一些接口已經(jīng)被標注為函數(shù)式接口的:

  1. java.lang.Runnable
  2. java.util.Comparator
  3. java.util.concurrent.Callable
  4. java.io.FileFilter
  5. java.security.PrivilegedAction
  6. java.beans.PropertyChangeListener

Java 8 中更是新增加了一個包 java.util.function,帶來了常用的函數(shù)式接口:

  1. Function<T, R> - 函數(shù):輸入 T 輸出 R
  2. BiFunction<T, U, R> - 函數(shù):輸入 T 和 U 輸出 R 對象
  3. Predicate<T> - 斷言/判斷:輸入 T 輸出 boolean
  4. BiPredicate<T, U> - 斷言/判斷:輸入 T 和 U 輸出 boolean
  5. Supplier<T> - 生產(chǎn)者:無輸入,輸出 T
  6. Consumer<T> - 消費者:輸入 T,無輸出
  7. BiConsumer<T, U> - 消費者:輸入 T 和 U 無輸出
  8. UnaryOperator<T> - 單元運算:輸入 T 輸出 T
  9. BinaryOperator<T> - 二元運算:輸入 T 和 T 輸出 T

另外還對基本類型的處理增加了更加具體的函數(shù)是接口,包括:BooleanSupplier, DoubleBinaryOperator, DoubleConsumer, DoubleFunction<R>, DoublePredicate, DoubleSupplier, DoubleToIntFunction, DoubleToLongFunction, DoubleUnaryOperator, IntBinaryOperator, IntConsumer, IntFunction<R>, IntPredicate, IntSupplier, IntToDoubleFunction, IntToLongFunction, IntUnaryOperator, LongBinaryOperator, LongConsumer,LongFunction<R>, LongPredicate, LongSupplier, LongToDoubleFunction,LongToIntFunction, LongUnaryOperator, ToDoubleBiFunction<T, U>, ToDoubleFunction<T>,ToIntBiFunction<T, U>, ToIntFunction<T>, ToLongBiFunction<T, U>, ToLongFunction<T> 。結合上面的函數(shù)式接口,對這些基本類型的函數(shù)式接口通過類名就能一眼看出接口的作用。

創(chuàng)建函數(shù)式接口

有時候我們需要自己實現(xiàn)一個函數(shù)式接口,做法也很簡單,首先你要保證此接口只能有一個函數(shù)操作,然后在接口類型上標注注解 @FunctionalInterface 即可。

類型推導

類型推導是 Lambda 表達式的基礎,類型推導的過程就是 Lambda 表達式的編譯過程。以下面的代碼為例:

Function<String, Integer> strToInt = str -> Integer.parseInt(str);
編譯期間,我理解的類型推導的過程如下:

  1. 先確定目標類型 Function
  2. Function 作為函數(shù)式接口,其方法簽名為:Integer apply(String t)
  3. 檢測 str -> Integer.parseInt(str) 是否與方法簽名匹配(方法的參數(shù)類型、個數(shù)、順序 和返回值類型)
  4. 如果不匹配,則報編譯錯誤

這里的目標類型是關鍵,通過目標類型獲取方法簽名,然后和 Lambda 表達式做出對比。

方法引用

方法引用(Method Reference)的基礎同樣是函數(shù)式接口,可以直接作為函數(shù)式接口的實現(xiàn),與 Lambda 表達式有相同的作用,同樣依賴于類型推導。方法引用可以看作是只調用一個方法的 Lambda 表達式的簡化。

方法引用的語法為: Type::methodName 或者 instanceName::methodName , 構造函數(shù)對應的 methodName 為 new。

例如上面曾用到例子:

Function<String, Integer> strToInt = str -> Integer.parseInt(str);

對應的方法引用的寫法為

Function<String, Integer> strToInt = Integer::parseInt;

根據(jù)方法的類型,方法引用主要分為一下幾種類型,構造方法引用、靜態(tài)方法引用、實例上實例方法引用、類型上實例方法引用等

構造方法引用

語法為: Type::new 。 如下面的函數(shù)為了將字符串轉為數(shù)組

方法引用寫法

Function<String, Integer> strToInt = Integer::new;

Lambda 寫法

Function<String, Integer> strToInt = str -> new Integer(str);

傳統(tǒng)寫法

Function<String, Integer> strToInt = new Function<String, Integer>() {
  @Override
  public Integer apply(String str) {
    return new Integer(str);
  }
};


數(shù)組構造方法引用

語法為: Type[]::new 。如下面的函數(shù)為了構造一個指定長度的字符串數(shù)組

方法引用寫法

Function<Integer, String[]> fixedArray = String[]::new;

方法引用寫法

Function<Integer, String[]> fixedArray = length -> new String[length];

傳統(tǒng)寫法

Function<Integer, String[]> fixedArray = new Function<Integer, String[]>() {
  @Override
  public String[] apply(Integer length) {
    return new String[length];
  }
};

靜態(tài)方法引用

語法為: Type::new 。 如下面的函數(shù)同樣為了將字符串轉為數(shù)組

方法引用寫法

Function<String, Integer> strToInt = Integer::parseInt;

Lambda 寫法

Function<String, Integer> strToInt = str -> Integer.parseInt(str);

傳統(tǒng)寫法

Function<String, Integer> strToInt = new Function<String, Integer>() {
  @Override
  public Integer apply(String str) {
    return Integer.parseInt(str);
  }
};

實例上實例方法引用

語法為: instanceName::methodName 。如下面的判斷函數(shù)用來判斷給定的姓名是否在列表中存在

List<String> names = Arrays.asList(new String[]{"張三", "李四", "王五"});
Predicate<String> checkNameExists = names::contains;
System.out.println(checkNameExists.test("張三"));
System.out.println(checkNameExists.test("張四"));

類型上實例方法引用

語法為: Type::methodName 。運行時引用是指上下文中的對象,如下面的函數(shù)來返回字符串的長度

Function<String, Integer> calcStrLength = String::length;
System.out.println(calcStrLength.apply("張三"));
List<String> names = Arrays.asList(new String[]{"zhangsan", "lisi", "wangwu"});
names.stream().map(String::length).forEach(System.out::println);

又比如下面的函數(shù)已指定的分隔符分割字符串為數(shù)組

BiFunction<String, String, String[]> split = String::split;
String[] names = split.apply("zhangsan,lisi,wangwu", ",");
System.out.println(Arrays.toString(names));

Stream 對象

概念

什么是 Stream ? 這里的 Stream 不同于 io 中的 InputStream 和 OutputStream,Stream 位于包 java.util.stream 中, 也是 java 8 新加入的,Stream 只的是一組支持串行并行聚合操作的元素,可以理解為集合或者迭代器的增強版。什么是聚合操作?簡單舉例來說常見的有平均值、最大值、最小值、總和、排序、過濾等。

Stream 的幾個特征:

單次處理。一次處理結束后,當前Stream就關閉了。
支持并行操作
常見的獲取 Stream 的方式

從集合中獲取

Collection.stream();
Collection.parallelStream();

靜態(tài)工廠

Arrays.stream(array)
Stream.of(T …)
IntStream.range()
這里只對 Stream 做簡單的介紹,下面會有具體的應用。要說 Stream 與 Lambda 表達式有什么關系,其實并沒有什么特別緊密的關系,只是 Lambda 表達式極大的方便了 Stream 的使用。如果沒有 Lambda 表達式,使用 Stream 的過程中會產(chǎn)生大量的匿名類,非常別扭。

舉例

以下的demo依賴于 Employee 對象,以及由 Employee 對象組成的 List 對象。

public class Employee {

  private String name;
  private String sex;
  private int age;

  public Employee(String name, String sex, int age) {
    super();
    this.name = name;
    this.sex = sex;
    this.age = age;
  }
  public String getName() {
    return name;
  }

  public String getSex() {
    return sex;
  }
  public int getAge() {
    return age;
  }
  @Override
  public String toString() {
    StringBuilder builder = new StringBuilder();
    builder.append("Employee {name=").append(name).append(", sex=").append(sex).append(", age=").append(age)
        .append("}");
    return builder.toString();
  } 
}
List<Employee> employees = new ArrayList<>();
employees.add(new Employee("張三", "男", 25));
employees.add(new Employee("李四", "女", 24));
employees.add(new Employee("王五", "女", 23));
employees.add(new Employee("周六", "男", 22));
employees.add(new Employee("孫七", "女", 21));
employees.add(new Employee("劉八", "男", 20));

打印所有員工

Collection 提供了 forEach 方法,供我們逐個操作單個對象。

employees.forEach(e -> System.out.println(e));
或者
employees.stream().forEach(e -> System.out.println(e));

按年齡排序

Collections.sort(employees, (e1, e2) -> e1.getAge() - e2.getAge());
employees.forEach(e -> System.out.println(e));
或者
employees.stream().sorted((e1, e2) -> e1.getAge() - e2.getAge()).forEach(e -> System.out.println(e));
打印年齡最大的女員工

max/min 返回指定排序條件下最大/最小的元素

Employee maxAgeFemaleEmployee = employees.stream()
    .filter(e -> "女".equals(e.getSex()))
    .max((e1, e2) -> e1.getAge() - e2.getAge())
    .get();
System.out.println(maxAgeFemaleEmployee);

打印出年齡大于20 的男員工

filter 可以過濾出符合條件的元素

employees.stream()
        .filter(e -> e.getAge() > 20 && "男".equals(e.getSex()))
        .forEach(e -> System.out.println(e));
打印出年齡最大的2名男員工

limit 方法截取有限的元素

employees.stream()
    .filter(e -> "男".equals(e.getSex()))
    .sorted((e1, e2) -> e2.getAge() - e1.getAge())
    .limit(2)
    .forEach(e -> System.out.println(e));

打印出所有男員工的姓名,使用 , 分隔

map 將 Stream 中所有元素的執(zhí)行給定的函數(shù)后返回值組成新的 Stream

String maleEmployeesNames = employees.stream()
    .map(e -> e.getName())
    .collect(Collectors.joining(","));
System.out.println(maleEmployeesNames);

統(tǒng)計信息

IntSummaryStatistics, DoubleSummaryStatistics, LongSummaryStatistics 包含了 Stream 中的匯總數(shù)據(jù)。

IntSummaryStatistics stat = employees.stream()
    .mapToInt(Employee::getAge).summaryStatistics();
System.out.println("員工總數(shù):" + stat.getCount());
System.out.println("最高年齡:" + stat.getMax());
System.out.println("最小年齡:" + stat.getMin());
System.out.println("平均年齡:" + stat.getAverage());

總結

Lambda 表達式確實可以減少很多代碼,能提高生產(chǎn)力,當然也有弊端,就是復雜的表達式可讀性會比較差,也可能是還不是很習慣的緣故吧,如果習慣了,相信會喜歡上的。凡事都有兩面性,就看我們如何去平衡這其中的利弊了,尤其是在一個團隊中。

以上就是對Java8 JavaLambda 的資料整理,后續(xù)繼續(xù)補充相關資料謝謝大家對本站的支持!

相關文章

  • 基于OpenCv與JVM實現(xiàn)加載保存圖像功能(JAVA?圖像處理)

    基于OpenCv與JVM實現(xiàn)加載保存圖像功能(JAVA?圖像處理)

    openCv有一個名imread的簡單函數(shù),用于從文件中讀取圖像,本文給大家介紹JAVA?圖像處理基于OpenCv與JVM實現(xiàn)加載保存圖像功能,感興趣的朋友一起看看吧
    2022-01-01
  • 關于jdk環(huán)境變量配置以及javac不是內部或外部命令的解決

    關于jdk環(huán)境變量配置以及javac不是內部或外部命令的解決

    這篇文章主要介紹了關于jdk環(huán)境變量配置以及javac不是內部或外部命令的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • java設計模式之外觀模式(Facade)

    java設計模式之外觀模式(Facade)

    這篇文章主要為大家詳細介紹了java設計模式之外觀模式Facade的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • springboot學習之Thymeleaf模板引擎及原理介紹

    springboot學習之Thymeleaf模板引擎及原理介紹

    本文主要介紹一下SpringBoot給我們推薦的Thymeleaf模板引擎,這模板引擎呢,是一個高級語言的模板引擎,他的這個語法更簡單而且功能更強大,對springboot?Thymeleaf模板引擎相關知識感興趣的朋友一起看看吧
    2022-02-02
  • java學習之猜數(shù)字小游戲

    java學習之猜數(shù)字小游戲

    這篇文章主要為大家詳細介紹了java學習之猜數(shù)字小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • Java中各種集合判空方法總結

    Java中各種集合判空方法總結

    最近接觸集合比較多,經(jīng)常對于集合是否為空做判斷,下面這篇文章主要給大家介紹了關于Java中各種集合判空方法總結的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2023-12-12
  • Java關鍵字volatile知識點總結

    Java關鍵字volatile知識點總結

    在本篇文章里小編給大家整理的是一篇關于Java關鍵字volatile知識點總結內容,有興趣的朋友們可以學習參考下。
    2021-01-01
  • Java基于ShardingSphere實現(xiàn)分庫分表的實例詳解

    Java基于ShardingSphere實現(xiàn)分庫分表的實例詳解

    ShardingSphere?已于2020年4月16日成為?Apache?軟件基金會的頂級項目,?它們均提供標準化的數(shù)據(jù)水平擴展、分布式事務和分布式治理等功能,可適用于如?Java?同構、異構語言、云原生等各種多樣化的應用場景,對ShardingSphere分庫分表相關知識感興趣的朋友一起看看吧
    2022-03-03
  • 在Android系統(tǒng)中解析XML文件的方法

    在Android系統(tǒng)中解析XML文件的方法

    這篇文章主要介紹了在Android系統(tǒng)中解析XML文件的方法,利用Java寫成的XmlPullParser解析器,需要的朋友可以參考下
    2015-07-07
  • 關于Java?float和double精度范圍大小

    關于Java?float和double精度范圍大小

    這篇文章主要介紹了關于Java?float和double精度范圍大小,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12

最新評論