一 、Lambda表達式前瞻知識
什么是Lambda表達式?
可以將Lambda表達式理解為一個匿名函數(shù); Lambda表達式允許將一個函數(shù)作為另外一個函數(shù)的參數(shù); 我們可以把 Lambda 表達式理解為是一段可以傳遞的代碼(將代碼作為實參),也可以理解為函數(shù)式編程,將一個函數(shù)作為參數(shù)進行傳遞。
為什么要引入Lambda表達式?
Lambda表達式能夠讓程序員的編程更加高效
lambda表達式和方法引用使用前提:函數(shù)式接口
1.@FunctionalInterface 語法格式嚴格要求當(dāng)前接口有且只能有一個尚未完成的缺省屬性為 public abstract 修飾方法。
2.函數(shù)式接口一般用于方法的增強,直接作為方法的參數(shù),實現(xiàn)函數(shù)式編程。
只有函數(shù)式接口的變量或者是函數(shù)式接口,才能夠賦值為Lambda表達式。這個接口中,可以有默認方法,或者是靜態(tài)方法。
二、Lambda表達式
1.Lambda表達式的基本語法
([Lambda參數(shù)列表,即形參列表]) -> {Lambda體,即方法體}
1.Lambda 表達式關(guān)注的是接口中方法的返回值和參數(shù),方法名不重要
2.使用 "->"將參數(shù)和實現(xiàn)邏輯分離;( ) 中的部分是需要傳入Lambda體中的參數(shù);{ } 中部分,接收來自 ( ) 中的參數(shù),完成一定的功能。
3.只有函數(shù)式接口的變量或者是函數(shù)式接口,才能夠賦值為Lambda表達式。這個接口中,可以有默認方法,或者是靜態(tài)方法。
2.四種lambda表達式
2.1無參數(shù)無返回值
//接口設(shè)計
@FunctionalInterface
interface A {
void 方法名真的沒有用();
}
//方法設(shè)計
public static void testLambda(A a) {
a.方法名真的沒有用();
}
//代碼實現(xiàn)
public static void main(String[] args) {
//1.匿名內(nèi)部類方法
//接口無法實例化,這里實例化的是 A 接口的實現(xiàn)類對象(該方法在jdk1.8以后被lambda表達式完虐)
testLambda(new A() {
//缺省屬性為abstract,需要重寫
@Override
public void 方法名真的沒有用() {
System.out.println("無參數(shù)返回值 匿名內(nèi)部類對象方法實現(xiàn)");
}
});
/*
2. Lambda 表達式實現(xiàn)
【分析】
void 方法名真的沒有用();
接口方法【返回值類型】 void,無返回值
接口方法【參數(shù)】 無參數(shù)
*/
testLambda(() -> {
System.out.println("Lambda 表達式初體驗");
});
//Lambda 表達式有且只有一行代碼,可以省略大括號
testLambda(() -> System.out.println("Lambda 表達式初體驗"));
2.2無參數(shù)有返回值
生產(chǎn)者接口
Supplier < T> T get() 無參有返回值的抽象方法;
//接口設(shè)計
@FunctionalInterface
interface Supplier<T> {
/**
* 無參數(shù)有返回值方法,泛型約束的是接口對應(yīng)的返回值數(shù)據(jù)類型,要求按照泛型約束返回對應(yīng)的數(shù)據(jù)內(nèi)容
*
* @return 返回一個數(shù)據(jù),符合泛型約束
*/
T get();
}
/*
* 當(dāng)前方法要求返回一個字符串?dāng)?shù)據(jù)內(nèi)容
*/
public static String testLambda(Supplier<String> s) {
return s.get();
}
public static void main(String[] args) {
/*
【分析】
T get(); ==> 泛型約束為 String ==> String get();
接口方法【返回值類型】 String
接口方法【參數(shù)】 無參數(shù)
Lambda 格式:() -> {必須返回一個 String 類型}
*/
String s1 = testLambda(() -> {
return "這里也是一個字符串";
});
System.out.println(s1);
/*
Lambda 優(yōu)化,只要 -> 之后是一個 字符串?dāng)?shù)據(jù)內(nèi)容就可以滿足當(dāng)前 Lambda 所需
可以省略 return ,前提是當(dāng)前 Lambda 有且只有一行代碼
*/
String s2 = testLambda(() -> "這里也是一個字符串");
System.out.println(s2);
/*
Lambda 內(nèi)部使用使用方法局部變量
*/
String str = "name=王小明&age=23&country=中國";
String s3 = testLambda(() -> {
// str 是當(dāng)前 main 方法局部變量,Lambda 內(nèi)部可以直接使用
String[] split = str.split("&");
return split[0];
});
System.out.println(s3);//返回王小明
}
2.3有參數(shù)無返回值
消費型接口
Consumer< T> void accept(T t)有參數(shù),無返回值的抽象方法;
@FunctionalInterface
interface Consumer<T> {
/**
* 消費者接口,數(shù)據(jù)最終處理接口,數(shù)據(jù)處理終止方法接口,對應(yīng)的方法要求方法有參數(shù)無返回值
*
* @param t 泛型數(shù)據(jù)數(shù)據(jù)類型 T ,支持任意類型,在接口約束之后,要求符合數(shù)據(jù)類型一致化要求
*/
void accept(T t);
}
/**
* 有參數(shù)無返回 Lambda 測試方法,方法參數(shù)是 String 類型和針對于 String 類型
* 進行數(shù)據(jù)處理的 Consumer 接口,Consumer 接口可以傳入實現(xiàn)類對象和 Lambda 表達式
*
* @param str 目標處理的 String 字符串?dāng)?shù)據(jù)
* @param handle 已經(jīng)約束為處理 String 類型數(shù)據(jù)的 Consumer 接口處理器
*/
public static void testLambda(String str, Consumer<String> handle) {
handle.accept(str);
}
public static void main(String[] args) {
/*
1、匿名內(nèi)部類 Low
*/
testLambda("孟州市炒面第一名", new Consumer<String>() {
@Override
public void accept(String t) {
System.out.println(t);
}
});
/*
2. Lambda 表達式
【分析】
void accept(T t); ==> 泛型約束為 String ==> void accept(String t);
接口方法【返回值】 void
接口方法【參數(shù)】 1 個參數(shù),String 類型
Lambda 格式
Lambda 小括號中的臨時變量名稱,沒有數(shù)據(jù)類型體現(xiàn),需要【聯(lián)想】目標方法數(shù)據(jù)類型
只按照參數(shù)的個數(shù)定義臨時小變量
(s) -> {大括號中無需返回值類型}
Lambda 表達式臨時變量 s 對應(yīng)的數(shù)據(jù)類型為 String 類型 【聯(lián)想可得】
*/
testLambda("lambda表達式需要聯(lián)想?。?!", (s) -> {
System.out.println(Arrays.toString(s.toCharArray()));
});
/*
Lambda 優(yōu)化
1. 代碼塊有且只有一行,可以省略大括號
2. 小括號中有且只有一個 參數(shù),可以省略小括號
【注意】
Lambda 承擔(dān)的角色是一個針對于 String 字符串的處理器
*/
testLambda("lambda表達式需要聯(lián)想!?。?, s -> System.out.println(Arrays.toString(s.toCharArray())));
}
2.4有參數(shù)有返回值
- 比較器接口
Comparator< T> int compare(T o1, T o2)有參,返回值類型為int - 斷定型接口(過濾器接口)
Predicate< T> boolean test(T t)有參,但是返回值類型是固定的boolean - 函數(shù)型接口(類型轉(zhuǎn)換器接口)
Function< T,R> R apply(T t)有參,有返回值的抽象方法
1.比較器接口
// 比較器接口
@FunctionalInterface
interface Comparator<T> {
/**
* 比較器接口要求的方法,參數(shù)是泛型參數(shù),用戶指定類型
*
* @param o1 用戶在使用接口時約束的泛型對應(yīng)具體數(shù)據(jù)類型參數(shù)
* @param o2 用戶在使用接口時約束的泛型對應(yīng)具體數(shù)據(jù)類型參數(shù)
* @return 返回值為 int 類型,0 表示兩個元素一致。
*/
int compare(T o1, T o2);
}
/**
* @author Anonymous 2023/3/3 11:30
*/
public class Demo1 {
public static void main(String[] args) {
Person[] array = new Person[5];
for (int i = 0; i < array.length; i++) {
int age = (int) (Math.random() * 50);
array[i] = new Person(i + 1, "張三", age, false);
}
/*
Lambda 分享
方法
int compare(T o1, T o2); ==> 泛型約束為 Person ==> int compare(Person o1, Person o2);
方法返回值 int 類型
方法參數(shù)
1. 2個參數(shù)
2. 參數(shù)數(shù)據(jù)類型都是 Person 類型
Lambda 格式
(o1, o2) -> {所需返回值為 int 類型}
*/
sortPersonArrayUsingComparator(array, (o1, o2) -> o1.getId() - o2.getId());
// Arrays.sort(array, (o1, o2) -> o1.getAge() - o2.getAge());
for (Person person : array) {
System.out.println(person);
}
}
/**
* 排序操作,排序數(shù)組為 Person 類型,排序規(guī)則使用自定義 Comparator 接口實現(xiàn),接口泛型約束 Person
* 類型
*
* @param array Person 類型數(shù)組
* @param condition 針對于 Person 類型數(shù)組的 Comparator 比較器接口實現(xiàn)
*/
public static void sortPersonArrayUsingComparator(Person[] array, Comparator<Person> condition) {
for (int i = 0; i < array.length - 1; i++) {
int index = i;
for (int j = i + 1; j < array.length; j++) {
/*
condition 是自定義 Comparator 排序接口方法,目前泛型約束為 Person 類型
int compare(T o1, T o2); ==> int compare(Person o1, Person o2);
當(dāng)前數(shù)組存儲的數(shù)據(jù)類型就是 Person 對象,可以作為 compare 方法參數(shù),同時
利用 compare 方法返回 int 類型數(shù)據(jù),作為排序算法規(guī)則的限制。
*/
if (condition.compare(array[index], array[j]) > 0) {
index = j;
}
}
if (index != i) {
Person temp = array[index];
array[index] = array[i];
array[i] = temp;
}
}
}
}
問題解答:為什么約束類型為Person
2.過濾器接口
// 過濾器接口,判斷器接口,條件接口
@FunctionalInterface
interface Predicate<T> {
/**
* 過濾器接口約束的方法,方法參數(shù)是用戶使用時約束泛型對應(yīng)具體數(shù)據(jù)參數(shù)
* 返回值類型是 boolean 類型,用于條件判斷,數(shù)據(jù)過來
*
* @param t 用戶約束泛型對應(yīng)的具體數(shù)據(jù)類型參數(shù)
* @return boolean 數(shù)據(jù),判斷結(jié)果反饋
*/
boolean test(T t);
}
public class Demo2 {
public static void main(String[] args) {
Person[] array = new Person[5];
for (int i = 0; i < array.length; i++) {
int age = (int) (Math.random() * 50);
array[i] = new Person(i + 1, "張三", age, false);
}
/*
Lambda 分析
boolean test(T t); ==> 泛型約束為 Person 類型 ==> boolean test(Person t);
方法返回值是 boolean
方法參數(shù)
1. 1 個
2. Person 類型
Lambda 格式
p -> {要求必須返回一個 boolean}
*/
Person[] temp = filterPersonArrayUsingPredicate(array, p -> p.getAge() > 10);
for (Person person : temp) {
System.out.println(person);
}
}
/**
* 過濾限定操作,利用 Predicate 過濾器接口限定數(shù)組內(nèi)容
*
* @param array Person 類型數(shù)組
* @param filter Predicate 過濾器參數(shù)
* @return 過濾限定之后的新數(shù)組
*/
public static Person[] filterPersonArrayUsingPredicate(Person[] array, Predicate<Person> filter) {
Person[] temp = new Person[array.length];
int count = 0;
for (int i = 0; i < array.length; i++) {
/*
Predicate 接口提供的方法是 boolean test(T t);
目前泛型約束之后是 boolean test(Person t);
判斷當(dāng)前 Person 對象是否滿足要求,如果滿足,存儲到 temp 數(shù)組中。
*/
if (filter.test(array[i])) {
temp[count++] = array[i];
}
}
return temp;
}
}
3.類型轉(zhuǎn)換器接口
// 類型轉(zhuǎn)換器接口
@FunctionalInterface
interface Function<T, R> {
R apply(T t);
}
public class Demo3 {
public static void main(String[] args) {
String str = "開封有個包青天";
/*
Lambda 分析
R apply(T t); ==> 泛型約束 T => String R => Integer
Integer apply(String t);
Lambda 格式
返回值類型 Integer
方法參數(shù)
1. 1個
2. String
s -> {必須返回 int 類型數(shù)據(jù)}
*/
int i = testLambda(str, s -> s.length());
System.out.println(i);
}
public static int testLambda(String str, Function<String, Integer> fun) {
return fun.apply(str);
}
}
三、方法引用(拓展):
當(dāng)Lambda表達式滿足某種條件的時候,使用方法引用,可以再次簡化代碼
1.構(gòu)造引用
當(dāng)Lambda表達式是通過new一個對象來完成的,那么可以使用構(gòu)造引用。文章來源:http://www.zghlxwxcb.cn/news/detail-765139.html
import java.util.function.Supplier;
public class TestLambda {
public static void main(String[] args) {
// Supplier<Student> s = () -> new Student();
Supplier<Student> s = Student::new;
}//實際過程:將new Student()賦值給了Supplier這個函數(shù)式接口中的那個抽象方法
}
2.類名::實例方法
Lambda表達式的的Lambda體也是通過一個對象的方法完成,但是調(diào)用方法的對象是Lambda表達式的參數(shù)列表中的一個,剩下的參數(shù)正好是給這個方法的實參。文章來源地址http://www.zghlxwxcb.cn/news/detail-765139.html
import java.util.TreeSet;
public class TestLambda {
public static void main(String[] args) {
TreeSet<String> set = new TreeSet<>((s1,s2) -> s1.compareTo(s2));
}
3.對象::實例方法
*/ //類名::實例方法
TreeSet<String> set = new TreeSet<>(String::compareTo);
set.add("Hello");
set.add("isea_you");
// set.forEach(t -> System.out.println(t));//Hello \n isea_you
set.forEach(System.out::println);
//(1)對象::實例方法,Lambda表達式的(形參列表)與實例方法的(實參列表)類型,個數(shù)是對應(yīng)
}
}
4.類名::靜態(tài)方法
package com.isea.java;
import java.util.stream.Stream;
public class TestLambda {
public static void main(String[] args) {
// Stream<Double> stream = Stream.generate(() -> Math.random());
// 類名::靜態(tài)方法, Lambda表達式的(形參列表)與實例方法的(實參列表)類型,個數(shù)是對應(yīng)
Stream<Double> stream = Stream.generate(Math::random);
stream.forEach(System.out::println);
}
}
到了這里,關(guān)于Java學(xué)習(xí)——lambda表達式的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!