函數(shù)式接口, 一般可以作為方法的參數(shù)和返回值類型
- 案例1:函數(shù)式接口作為方法的參數(shù)
#自定義函數(shù)式接口
package FunctionInterface;
public interface MyFunctionInterface {
public abstract void method();
}
public class functionDemo {
public static void show(MyFunctionInterface myFunctionInterface) {
myFunctionInterface.method();
}
public static void main(String[] args) {
// 方式1
// 調(diào)用show方法,參數(shù)是一個接口肥惭,可以傳遞接口的匿名內(nèi)部類
show(new MyFunctionInterface(){
@Override
public void method() {
System.out.println("使用匿名內(nèi)部類重寫抽象方法");
}
});
// 方式2
// Lambda表達(dá)式
show(() ->{
System.out.println("Lambda表達(dá)式實(shí)現(xiàn)");
});
}
- 函數(shù)式接口作為參數(shù)
public class functionDemo {
public static void threadStart(Runnable run) {
new Thread(run).start();
}
// 方式1:匿名內(nèi)部類
threadStart(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "啟動了");
}
});
// 注意:參數(shù)Runnabl 一個函數(shù)式接口窃植,并且只有一個抽象方法(run),可以傳遞Lambda表達(dá)式
//方式2: Lambda表達(dá)式
threadStart(() -> System.out.println(Thread.currentThread().getName() + "啟動了"));
}
輸出:
Thread-0啟動了
Thread-1啟動了
- 案例2:函數(shù)式接口作為返回值
# 對字符串按照字符長度倒序
package FunctionInterface;
import java.util.Arrays;
import java.util.Comparator;
public class LambdaReturn {
public static Comparator<String> getComparator(){
//方式1:方法的返回值類型是一個接口鹤树,我們可以返回這個接口的匿名內(nèi)部類
/*
return new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
// 按照字符串的降序排列
return o2.length() - o1.length();
}
};
*/
// 方式1: Lambda表達(dá)式
return (String o1, String o2) -> {
// 按照字符串的降序排列
return o2.length() - o1.length();
};
// Lambda優(yōu)化
// return (o1, o2) -> o2.length() - o1.length();
}
public static void main(String[] args) {
// 函數(shù)式接口作為返回值
String[] strList = {"abc", "bcd", "wudy", "petwr", "world"};
System.out.println("排序前=" + Arrays.toString(strList));
Arrays.sort(strList, getComparator());
System.out.println("排序后=" + Arrays.toString(strList));
}
}
輸出:
排序前=[abc, bcd, wudy, petwr, world]
排序后=[petwr, world, wudy, abc, bcd]
- 案例3: Lambda延遲執(zhí)行
- 有些場景的代碼執(zhí)行后驹针,結(jié)果一定會被使用吃溅,從而造成性能浪費(fèi)风罩,而Lambda是延遲執(zhí)行的陨亡,正好可以作為解決方案
性能浪費(fèi)的日志案例:對日志消息進(jìn)行拼接后,在滿足條件的情況下進(jìn)行打印輸出
package FunctionInterface;
public class LambdaDelay {
public static void main(String[] args) {
String msg1 = "hello";
String msg2 = "world";
String msg3 = "java";
showLog(2, msg1 + msg2 + msg3);
}
public static void showLog(int level, String msg) {
if (level == 1) {
System.out.println("日志級別等于1" + msg);
}
}
注意: 上述代碼存在的問題: 拼接的字符串在level != 1 的時候并沒有用到辛慰,存在性能浪費(fèi)
- 優(yōu)化如下:
- 使用Lambda優(yōu)化日志案例
特點(diǎn):延時加載, 定義一個顯式日志的方法区匠,方法的參數(shù)傳遞日志的等級和MessageBuilder接口
使用Lambda表達(dá)式作為參數(shù)傳遞,僅僅是把參數(shù)傳遞到showLog方法中
只有滿足條件(日志等級是1)帅腌,才會調(diào)用接口MessageBuilder中的方法messageBuilder
如果不滿足條件驰弄,日志的等級不是1,那么接口MessageBuilder中的方法messageBuilder不會執(zhí)行
所以拼接字符串的代碼也不會執(zhí)行所以不會存在性能的浪費(fèi)
package FunctionInterface;
@FunctionalInterface
public interface MessageBuilder {
// 定義一個拼接消息的抽象方法, 返回被拼接的消息
public abstract String builderMessage();
}
package FunctionInterface;
public class LambdaDelay {
public static void main(String[] args) {
String msg1 = "hello";
String msg2 = "world";
String msg3 = "java";
showLog(1, () -> {
return msg1 + msg2 + msg3;
});
}
private static void showLog2(int level, MessageBuilder messageBuilder) {
if (1 == level) {
System.out.println("測試啥時候進(jìn)來這里啊!");
System.out.println(messageBuilder.builderMessage());;
}
}
結(jié)論: 當(dāng)level==2的時候速客,不會進(jìn)入Lambda表達(dá)式中戚篙,就不會執(zhí)行字符串拼接,從而節(jié)省性能
- 案例4: 使用Supplier接口作為方法參數(shù)類型
Supplier 被稱之為生產(chǎn)型接口挽封,指定接口的范型是什么類型已球,那么接口中的get方法就會生產(chǎn)什么類型的數(shù)據(jù)
package FunctionInterface;
import java.util.function.Supplier;
public class SupplierDemo {
public static void main(String[] args) {
// 調(diào)用getSupplier方法, 方法的參數(shù)Supplier是一個函數(shù)式接口辅愿,所以可以傳遞Lambda表達(dá)式
String name = getSupplier(() -> {
return "wudy";
});
//String name = getSupplier(() -> "wudy");
System.out.println(name);
}
public static String getSupplier(Supplier<String> supplier) {
return supplier.get();
}
}
輸出:
wudy
- Supplier接口作為方法參數(shù)類型, 通過Lambda表達(dá)式求出int數(shù)組中的最大值
package FunctionInterface;
import java.util.function.Supplier;
public class SupplierDemo {
public static void main(String[] args) {
Integer[] list = {88, 10, -12, -34, 0, 65, 102};
int maxValue = getMax(() -> {
System.out.println("second");
int max = list[0];
for (int i: list) {
if (i > max) {
max = i;
}
}
return max;
});
System.out.println(maxValue);
}
public static Integer getMax(Supplier<Integer> supplier) {
System.out.println("first");
return supplier.get();
}
}
輸出:
first
second
102
Consumer接口是一個消費(fèi)型接口智亮,范型指定什么類型,就可以使用accept方法消費(fèi)什么類型的數(shù)據(jù)
- 案例5: Consumer反轉(zhuǎn)字符串
package FunctionInterface;
import java.util.function.Consumer;
public class ConsumerDemo {
public static void main(String[] args) {
method("wudy", (String name) -> {
// 重寫accept
// 反轉(zhuǎn)字符串
String revName = new StringBuffer(name).reverse().toString();
System.out.println(revName);
});
}
public static void method(String name, Consumer<String> consumer){
consumer.accept(name);
}
}
輸出:
yduw
- AndThen方法: 需要兩個Consumer接口点待,可以把兩個Consumer接口組合到一起阔蛉,再對數(shù)據(jù)進(jìn)行消費(fèi)
package FunctionInterface;
import java.util.function.Consumer;
public class ConsumerAndThen {
public static void main(String[] args) {
method("Hello World", (String name) -> {
System.out.println("執(zhí)行con1=" + name.toUpperCase());
}, (String name) -> {
System.out.println("執(zhí)行con2=" + name.toLowerCase());
});
}
public static void method(String s, Consumer<String> con1, Consumer<String> con2){
// 先執(zhí)行con2消費(fèi)數(shù)據(jù),再執(zhí)行con1消費(fèi)數(shù)據(jù)
con2.andThen(con1).accept(s);
}
}
輸出:
執(zhí)行con2=hello world
執(zhí)行con1=HELLO WORLD
- AndThen方法: 格式化打印信息
- 將下面的字符串按照格式"姓名:XX癞埠。性別:XX" 的格式打印出來状原,要求將打印姓名的動作作為第一個Consumer接口的Lambda實(shí)例,
將打印性別的動作作為第二個Consumer接口的Lambda實(shí)例苗踪,將兩個Consumer接口按照順序拼接到一起
package FunctionInterface;
import java.util.function.Consumer;
public class FormatPrint {
public static void main(String[] args) {
String[] strList = {"wudy,男","peter,女","timo,女"};
for (String str: strList) {
printInfo(str, (String name) -> {
name = str.split(",")[0];
System.out.print("姓名:" + name);
}, (String sex) -> {
sex = str.split(",")[1];
System.out.println("颠区。性別:" + sex + "。");
});
}
}
public static void printInfo(String str, Consumer<String> con1, Consumer<String> con2) {
con1.andThen(con2).accept(str);
}
}
輸出:
姓名:wudy通铲。性別:男毕莱。
姓名:peter。性別:女颅夺。
姓名:timo朋截。性別:女。
- 有時候我們需要對某種類型的數(shù)據(jù)進(jìn)行判斷吧黄,從而得到一個boolean值結(jié)果
package FunctionInterface;
import java.util.function.Predicate;
public class PredicateDemo {
public static void main(String[] args) {
String str = "macBookPro";
boolean b = checkString(str, (String s) -> s.length() >15);
System.out.println(b);
}
public static boolean checkString(String str, Predicate<String> predicate) {
return predicate.test(str);
}
}
輸出:
false