Java8方法引用
方法引用Demo詳解
通過5種語法使用方法引用
方法引用使用總結
- 在Java8中方法引用Demo詳解
1.1 方法引用出現的背景
在使用Lambda表達式的時候,我們實際上傳遞進去的代碼就是一種解決方案:拿什麽參數做什麽操作。
那麽考慮一種情況:如果我們在Lambda中所指定的操作方案,已經有地方存在相同方案,那是否還有必要再寫重復邏輯呢?
1.2 問題的引出?
//函數式接口,用於打印字符串. @FunctionalInterface interface Print{ public void print(String s); } //使用lambda表達式完成案例測試. public class PrintDemo { public static void main(String[] args) { //Lambda方式解決 print(s -> {System.out.println(s);}, "hello"); } public static void print(Print p,String s){ p.print(s); } } ? ? 輸出結果: hello
1.3 問題的發現與解決
這段代碼的問題在於,對String進行控制臺打印輸出的操作方案,明明已經有了現成的實現,那就是System.out對象中的println(String)方法。既然Lambda希望做的事情就是調用println(String)方法,那何必自己手動調用呢?
能否省去Lambda的語法格式(盡管它已經相當簡潔)呢?只要“路由”過去就好了:
//函數式接口,用於打印字符串. @FunctionalInterface interface Print{ public void print(String s); } //使用lambda表達式完成案例測試. public class PrintDemo { public static void main(String[] args) { //方法引用解決方式 //請註意其中的雙冒號“::”寫法,這被稱為“方法引用”,而雙冒號是一種“引用運算符”。 print(System.out :: print,"world"); } public static void print(Print p,String s){ p.print(s); } } ? ? 輸出結果: world
1.4 方法引用案例的總結
以上例中,System.out對象中有一個重載的println(String)方法恰好就是我們所需要的。那麽對於printString方法的函數式接口參數,對比下面兩種寫法:
Lambda表達式:s -> System.out.println(s);
方法引用:System.out::println
第一種語義是指:拿到參數之後經Lambda之手,繼而傳遞給System.out.println方法去處理。第二種等效寫法的語義是指:直接讓System.out中的println方法來取代Lambda。兩種寫法的執行效果完全一樣,而第二種方法引用的寫法復用了已有方案,更加簡潔。1.5 引用運算符
2.通過5種語法使用方法引用
2.1 通過對象名引用成員方法
?
//函數式接口
@FunctionalInterface
interface Printable{
public void print(String s);
}
?
//已存在的類,類中有打印字符串的方法.
class AlreadyExistPrint{
public void PrintString(String s){
System.out.println(s);
}
?
?
//測試通過對象名進行方法引用.
public class ObjectMethodReference {
public static void main(String[] args) {
//通過對象名引用方法
AlreadyExistPrint ap = new AlreadyExistPrint();
print(ap :: PrintString,"java");
}
public static void print(Printable p,String s){
p.print(s);
}
?
}
?
輸出結果:
java
2.2 通過類名引用靜態方法
//函數式接口
@FunctionalInterface
interface MyMath{
int max(int a, int b);
}
?
//已存在的類
這裏使用JDK提供的Math類中的靜態方法max(int a,int b);
?
?
//測試通過類名引用靜態方法.
public class ClassStaticMethod {
public static void main(String[] args) {
//通過Math類的類名引用靜態方法max();
int max = getMax(Math :: max, 10, 20);
System.out.println(max);
}
public static int getMax(MyMath lambda ,int a,int b){
return lambda.max(a, b);
}
?
}
?
輸出結果:
20
2.3 通過類名引用成員方法
/*
成員方法需要依托對象才可以執行,所以當並不存在對象時,成員方法無法執行。
如果希望成員方法的引用中僅出現類名稱而不出現對象名稱,情況則要復雜一些:
必須為其指定一個用來執行成員方法的對象實例。
*/
?
//在函數式接口中的參數裏加入對象實例:
@FunctionalInterface
interface Printable{
public void print(AlreadyExistPrint a ,String s);
}
?
//已存在的類
class AlreadyExistPrint{
public void PrintString(String s){
System.out.println(s);
}
?
}
?
//測試通過類名引用成員方法.
public class ClassMethod {
public static void main(String[] args) {
//通過類名引用成員方法;
//lambda方式實現:
//語義解析: 拿著對象a去調用a的print方法打印s
print((a,s) -> {a.PrintString(s);},new AlreadyExistPrint(),"hello");
//簡化寫法: 方法引用 (通過類名引用成員方法)
print(AlreadyExistPrint :: PrintString,new AlreadyExistPrint(),"hello");
}
public static void print(Printable p ,AlreadyExistPrint a,String s){
p.print(a,s);
}
?
}
?
輸出結果:
hello
hello
2.4 通過super引用成員方法
//函數式接口
@FunctionalInterface
interface Eat{
void eat(String food);
}
?
//已存在的類
class Animal{
public void eat(String food){
System.out.println("吃:"+food);
}
}
?
//Animal的子類
class Cat extends Animal{
@Override
public void eat(String food) {
//通過super引用父類的方法.
method(super :: eat,food);
}
public void method(Eat e, String s){
e.eat(s);
}
}
?
?
//測試通過類名引用成員方法.
public class SuperMethod {
public static void main(String[] args) {
Cat c = new Cat();
c.eat("魚");
}
?
}
?
輸出結果:
吃魚
2.5通過this引用成員方法
//函數式接口
interface shopping {
void buy(int money);
}
?
//已存在的類
class Man {
//男人將來都要買個屬於自己的房子.
public void buyHouse(int money) {
System.out.println("買套房子消費:"+money);
}
//結婚就得購物,買買買啊.
public void marry(shopping lambda,int money) {
lambda.buy(money);
}
//開心方法.男人要想開心.就得結婚
public void beHappy() {
//通過this引用成員方法.
marry(this::buyHouse,1000000);
}
}
?
?
//測試通過類名引用成員方法.
public class ThisMethod {
?
public static void main(String[] args) {
Man man = new Man();
man.beHappy();
}
}
?
?
輸出結果:
買套房子消費:1000000
3.方法引用使用總結
? (1) Lambda表達式:s -> System.out.println(s); (2) 方法引用:System.out::println
第一種語義是指:拿到參數之後經Lambda之手,繼而傳遞給System.out.println方法去處理。
?
第二種等效寫法的語義是指:直接讓System.out中的println方法來取代Lambda。
兩種寫法的執行效果完全一樣,而第二種方法引用的寫法復用了已有方案,更加簡潔。
?
函數式接口是Lambda的基礎,而方法引用是Lambda的孿生兄弟。
Java8方法引用