lambda表達式是函數式程式設計的核心,即隐式函數,沒有函數名,隻有函數體。
lambda表達式特點
(1)代碼簡單
(2) 對象不變性
lambda表達式的方法引用
(1)靜态方法:ClassName::methodName
(2)執行個體方法:instance::methodName
(3)超類的執行個體方法:super::methodName
(4)類型上的類型引用:ClassName::methodName
(5)構造方法引用:Class::new
(6)數組構造方法引用:TypeName[]::new
重點:通過@FunctionalInterface類型接口,定義構造函數:
class User{
private int id;
private String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
}
class ConstrMethodRef{
// 通過 User 的工廠類 UserFactory(函數式接口),使用User::new建立接口執行個體時,
// 系統會根據 UserFacroty.create() 的函數簽名選擇合适的 User 構造函數
@FunctionalInterface
interface UserFactory<U extends User>{
// 函數式接口定義:隻有一個抽象方法;其它(靜态、預設)方法不做限制
U create(int id, String name);
}
static UserFactory<User> userRef = User::new;
public static void main(String[] args) {
List<User> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(userRef.create(i, "xiao" + Integer.toString(i)));
}
list.stream().map(User::getName).forEach(System.out::print);
}
}
第二次結果還是原數組,說明函數式程式設計的不變性(是以函數式并行程式設計不用考慮線程安全性問題,因為每個對象都是不變的);
int[] nums = {1, 2, 3, 4};
String[] strs = {"xsx", "csw", "dwfwfve", "efwe", "frwqweqa"};
// 1.将所有元素 +1,并列印;
Arrays.stream(nums).map((x) -> x = x + 1).forEach(System.out::print); // {2,3,4,5}
// 2.傳入的還是 nums,即使 上一條語句 執行過了,是以列印的還是原數組
Arrays.stream(nums).forEach(System.out :: print); // {1,2,3,4}
// 3.元素為奇數 則加1,列印
Arrays.stream(nums).map(x -> (x % 2 == 0 ? x : x + 1)).forEach(System.out::println);
// 4.排序時的比較器(對strs字元串數組排序,規則:先按字元串長度升序,再按大小寫不敏感的字母順序排序)
Arrays.sort(strs, Comparator.comparingInt(String::length).thenComparing(String.CASE_INSENSITIVE_ORDER));
// 5.
流式程式設計的演變:
// 1.通過臨時執行個體化一個 Consumer 對象,重寫其中的方法,實作流式程式設計
Arrays.stream(strs).forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
// 2.推斷Consumer接口,省略Consumer執行個體
Arrays.stream(strs).forEach((final String x) -> { System.out.println(x); });
// 3.省略 參數類型、final 和 大括号;
Arrays.stream(strs).forEach((x) -> System.out.println(x));
// 4.可以使用方法引用的,直接使用方法引用
Arrays.stream(strs).forEach( System.out::println);
// 5. 使用
// 通過 Consumer 定義兩個方法引用
IntConsumer outPrint = System.out::println;
IntConsumer errPrint = System.err::println;
// 直接在stream中使用定義的方法引用
Arrays.stream(nums).forEach(outPrint.andThen(errPrint));
并行流
// 1.擷取指定範圍内的質數總數
IntStream.range(1, 10000).parallel().filter(PrimeUtil::isPrime).count();
// 2.從集合得到并行流
double avg = list.parallelStream().mapToInt(s -> s.id).average().getAsDouble();
// 3.并行排序
Arrays.parallelSort(nums);
// 4.并行指派
Arrays.parallelSetAll(nums, (i) -> new Random().nextInt());
lambda表達式實作
lambda表達式的實作類似于匿名類的實作,隻是寫法上有所差別,通過編譯反編譯lambda表達式,可以清楚看到。
問題:如何編譯、反編譯、檢視lambda表達式的實作方式?