一、集合遍歷與Lambda表達式 引入
package com.java.design.java8;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.*;
import java.util.function.Consumer;
/**
* @author 陳楊
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class ErgodicList {
@Test
public void testErgodicList() {
// 直接構造集合對象 保證了集合size>0
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
System.out.println("---------------------------傳統for循環--------------------\n");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("---------------------------增強for循環--------------------\n");
for (Integer i : list) {
System.out.println(i);
}
System.out.println("---------------------------迭代器-------------------------\n");
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
Integer integer = iterator.next();
System.out.println(integer);
}
System.out.println("---------------------------forEach------------------------\n");
list.forEach(new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
System.out.println(integer);
}
});
二、 @FunctionalInterface函數式接口與Lambda表達式
1、概念
// Consumer @FunctionalInterface函數式接口
// Conceptually, a functional interface has exactly one abstract method.
// 從概念上看,一個函數式接口有且只有一個精確的抽象方法
// 從java8開始 接口中不僅僅存在抽象方法 還能存在有具體實現的方法(默認方法)
2、 函數式接口的區分
// Since {@linkplain java.lang.reflect.Method#isDefault()
// default methods} have an implementation, they are not abstract. If
// an interface declares an abstract method overriding one of the
// public methods of {@code java.lang.Object}, that also does
// <em>not</em> count toward the interface's abstract method count
// since any implementation of the interface will have an
// implementation from {@code java.lang.Object} or elsewhere.
// 因為java.lang.reflect.Method#isDefault() default methods 有一個實現 所以不是抽象的
// 如果一個接口聲明一個抽象方法,其實現了java.lang.Object類中public方法:不計入抽象方法的個數
3、函數式接口的實例化方式
// Note that instances of functional interfaces can be created with
// lambda expressions, method references, or constructor references.
// 函數式接口的實例化: lambda表達式 方法引用 構造方法引用
4、函數式接口中的默認方法
// default void forEach(Consumer<? super T> action) {
// Objects.requireNonNull(action);
// for (T t : this) {
// action.accept(t);
// }
// }
// action 針對每個元素 執行的動作行為
// default 修飾接口 已實現的默認方法
5、總結與思考
// 1、如果一個接口中有且只有一個抽象方法 則其為一個函數式接口
// 2、如果一個接口上聲明了@FunctionalInterface注解 則編譯器會按照函數式接口的定義來要求該接口
// If a type is annotated with this annotation type, compilers are
// required to generate an error message unless:
// (1)The type is an interface type and not an annotation type, enum, or class.
// (2)The annotated type satisfies the requirements of a functional interface.
// However, the compiler will treat any interface meeting the
// definition of a functional interface as a functional interface
// regardless of whether or not a {@code FunctionalInterface}
// annotation is present on the interface declaration.
// 3、如果接口上只有一個抽象方法,但我們沒有對其加上@FunctionalInterface 編譯器仍然將其看作函數式接口
// 加上注解后 一目了然 如果沒有滿足強制性要求 則會拋出錯誤信息
// 4、只有一個抽象方法的接口 有必要加上 @FunctionalInterface 如 Runnable接口
// 5、所有的函數式接口 都可以使用lambda表達式 實現(表達易懂 簡單)
三、函數式接口實例化 之 Lambda表達式
System.out.println("--------------------lambda創建函數式接口實例---------------\n");
list.forEach(i -> {
// 若能推斷出i的類型 不需要聲明
// 如不能推斷出(Integer i)->{}
System.out.println(i);
});
四、在排序過程中 Lambda表達式的 演變
System.out.println("--------------------------lambda排序-----------------------\n");
// Collections.sort(list, new Comparator<Integer>() {
// @Override
// public int compare(Integer o1, Integer o2) {
// return o2.compareTo(o1);
// }
// });
// Collections.sort(list,(String o1, String o2)->{return o2.compareTo(o1);});
// Collections.sort(list, (o1, o2) -> { return o2.compareTo(o1); });
// statement { return o2.compareTo(o1); }
// expression o2.compareTo(o1)
// Collections.sort(list,(String::compareTo));
// Collections.sort(list,Collections.reverseOrder());
Collections.sort(list, (o1, o2) -> o2.compareTo(o1));
System.out.println(list);
五、函數式接口實例化 之 方法引用
System.out.println("--------------------方法引用創建函數式接口實例--------------\n");
list.forEach(System.out::println);
}
}
六、深入理解Lambda表達式
// lambda表達式:
// 1、從函數式編程角度來看:
// lambda表達式為Java添加了函數式編程的新特性 函數升格成為一等公民
// 在函數作為一等公民的語言 如Python中 lambda表達式為函數類型
// 但在java中 lambda表達式是對象類型 依賴於函數式接口Functional Interface
// 2、lambda表達式書寫
// lambda表達式形式 () -> {} 必需根據上下文確定其匿名函數類型 函數方法 -> 函數實現
// () 省略 參數只有一個且類型可根據上下文推導
// {} 省略 方法體主體只有一條語句,返回值類型與主體表達式(匿名函數)一致
// 3、進一步理解lambda表達式
// lambda表達式傳遞行為action 不僅僅是值的傳遞 (類比Node.js的事件驅動 與 回調函數callback)
// lambda表達式替換前: 事先定義對象及所持有的方法 根據 “對象.方法” 進行方法的調用 預先定義好的action
// lambda表達式替換后: {} 方法調用 R apply(T t); 事先不知道action 僅在調用時才知道 action
// 提升抽象層次 API重用性 使用靈活