目錄
前言:
方法引用:
方法引用基本概念:
方法可以被引用的條件:
方法引用的種類(lèi):
方法引用的優(yōu)點(diǎn):
總結(jié):
前言:
方法引用作為一個(gè)重要的知識(shí)點(diǎn),雖然他使用起來(lái)很復(fù)雜,而且會(huì)降低代碼的可讀性,但是如果用好了方法引用,我們也會(huì)獲得不錯(cuò)的效率,因此我們?cè)诮裉鞂榇蠹抑v解什么是方法引用。
方法引用:
方法引用基本概念:
我們用一張圖就很好的解釋了什么叫做方法引用,而官方對(duì)于方法引用的定義為:
Java中,方法引用是一種簡(jiǎn)潔的寫(xiě)法,用于直接引用現(xiàn)有方法,而不是調(diào)用它們。它提供了一種更簡(jiǎn)潔、易讀的方式來(lái)傳遞方法作為參數(shù)或在函數(shù)式接口中使用。
總而言之:方法引用就是我們把已經(jīng)有的方法拿過(guò)來(lái),當(dāng)作函數(shù)式接口中的抽象方法的方法體。
我們舉一個(gè)例子:
假設(shè)要對(duì)一個(gè)式子進(jìn)行排序,我們用lambda表達(dá)式的寫(xiě)法,可以寫(xiě)為:
Arrays.sort(arr,new Comparator<Integer>(){
@override
public int compare (Integer o1 , Integer o2)
{
return o2-o1;
}
});
而如果此時(shí)我們的代碼中就已經(jīng)有一個(gè)排序的方法 subraction:
public int subraction (int n1.int n2)
{
return n2-n1;
}
那么我們就可以直接在排序函數(shù)中直接拿過(guò)來(lái)用:
Arrays.sort(arr,方法所在類(lèi)名::subtraction);
//用我們已經(jīng)實(shí)現(xiàn)的方法subtraction作為排序的規(guī)則
其實(shí)這就是方法的引用。但是 不是所有的方法都可以引用的!
方法可以被引用的條件:
在Java中,方法引用要滿(mǎn)足以下條件才能被引用:
1. 方法引用必須引用一個(gè)已存在的方法。也就是說(shuō),被引用的方法必須已經(jīng)被定義。
2. 方法引用的參數(shù)類(lèi)型和數(shù)量必須與函數(shù)式接口中的抽象方法的參數(shù)類(lèi)型和數(shù)量相匹配。也就是說(shuō),被引用的方法的參數(shù)列表要與函數(shù)式接口中的方法參數(shù)列表完全匹配。
3. 方法引用的返回類(lèi)型必須與函數(shù)式接口中的抽象方法的返回類(lèi)型相匹配。也就是說(shuō),被引用的方法的返回類(lèi)型要與函數(shù)式接口中的方法返回類(lèi)型完全匹配。
4. 方法引用必須在上下文中根據(jù)目標(biāo)類(lèi)型進(jìn)行推斷。也就是說(shuō),編譯器必須能夠根據(jù)方法引用的上下文確定需要引用哪個(gè)方法。
需要注意的是,方法引用可以用于函數(shù)式接口中的抽象方法,包括Lambda表達(dá)式和方法引用在內(nèi)。函數(shù)式接口是只有一個(gè)抽象方法的接口,可以使用@FunctionalInterface注解來(lái)標(biāo)記。
方法引用的種類(lèi):
1.引用靜態(tài)方法。
? ? ? ? 格式:類(lèi)名::靜態(tài)方法
? ? ? ? 例子:Integer::parseInt
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "1", "2", "3", "4", "5");
//普通方法
list.stream().map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
int i = Integer.parseInt(s);
return i;
}
}).forEach(s-> System.out.println(s));
//方法引用
list.stream().map(Integer::parseInt).forEach(s-> System.out.println(s));
}
}
2.引用成員方法。
? ? ? ? 格式:對(duì)象::成員方法
? ? ? ? 1??其他類(lèi):? ?其他類(lèi)對(duì)象:: 方法名
案例:從一組字符串姓名中選出姓張且名字是三個(gè)字的人:
創(chuàng)建其他類(lèi):
public class Stringoperation {
public boolean stringjudge(String s) {
return s.startsWith("張")&& s.length()==3;
}
}
引用其他類(lèi)中的方法:
public static void main(String[] args) {
//1.創(chuàng)建集合并添加數(shù)據(jù)
ArrayList<String>list= new ArrayList<>();
Collections.addAll(list,"張無(wú)忌","周芷若","張敏","張強(qiáng)","張三豐");
//普通寫(xiě)法
list.stream().filter(s->s.startsWith("張")).filter(s->s.length()==3).forEach(s-> System.out.println(s));
//匿名內(nèi)部類(lèi)寫(xiě)法
list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("張")&& s.length()==3;
}
}).forEach(s-> System.out.println(s));
//方法引用
list.stream().filter(new Stringoperation()::stringjudge).forEach(s-> System.out.println(s));
}
?? ? ? ?2??本類(lèi):? ? ? ? ? this::方法名? (引用處不能是靜態(tài)方法)
import java.util.function.Consumer;
public class test07 {
public void doSomething() {
Consumer<String> consumer = this::printMessage; // 使用this::printMessage引用本類(lèi)方法
consumer.accept("Hello, world!");
}
public void printMessage(String message) {
System.out.println(message);
}
public static void main(String[] args) {
test07 obj = new test07();
obj.doSomething();
}
}
?TIPS:
? ? ? ? this::方法名? 這種形式是不可以在靜態(tài)main方法中實(shí)現(xiàn)的,這是因?yàn)閙ain有前綴static,使得main方法變?yōu)榱遂o態(tài)方法,而靜態(tài)方法中是沒(méi)有this指針的,如果想要在靜態(tài)方法中使用本類(lèi)方法,就要重新創(chuàng)建一個(gè)本類(lèi)的對(duì)象,然后再引用。
public class test06 {
public static void main(String[] args) {
//1.創(chuàng)建集合并添加數(shù)據(jù)
ArrayList<String>list= new ArrayList<>();
Collections.addAll(list,"張無(wú)忌","周芷若","張敏","張強(qiáng)","張三豐");
//方法引用
list.stream().filter(new test06()::stringjudge).forEach(s-> System.out.println(s));
}
public boolean stringjudge(String s) {
return s.startsWith("張")&& s.length()==3;
}
}
? ? ? ? 3??父類(lèi):? ? ? ? super::方法名 (引用處不能是靜態(tài)方法)? ? ? ? ? ? ? ? ? ? ? ??
class Parent {
public void printMessage() {
System.out.println("Hello from Parent class");
}
}
class Child extends Parent {
public void printMessage() {
// 使用super::printMessage引用父類(lèi)的方法
Runnable runnable = super::printMessage;
runnable.run();
}
public static void main(String[] args) {
Child child = new Child();
child.printMessage();
}
}
3.引用構(gòu)造方法。
????????格式:類(lèi)名:: new
? ? ? ? 范例:Student :: new
class Person {
private String name;
public Person(String name) {
this.name = name;
}
public void introduce() {
System.out.println("Hello, my name is " + name);
}
}
interface PersonFactory {
Person create(String name);
}
class Example {
public static void main(String[] args) {
// 使用構(gòu)造方法引用創(chuàng)建Person對(duì)象
PersonFactory factory = Person::new;
Person person = factory.create("Alice");
person.introduce();
}
}
4.使用類(lèi)名引用成員方法
? ? ? ? 格式:類(lèi)名::成員方法
? ? ? ? 范例:String::substring
public class test08 {
public static void main(String[] args) {
//1.創(chuàng)建集合對(duì)象并且添加對(duì)象
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "aaa", "bbb", "ccc");
//2.變成大寫(xiě)之后再輸出
//匿名內(nèi)部類(lèi)寫(xiě)法
list.stream().map(new Function<String, String>() {
@Override
public String apply(String s) {
return s.toUpperCase();
}
}).forEach(s -> System.out.println(s));
//引用類(lèi)中的方法
list.stream().map(String::toUpperCase).forEach(s -> System.out.println(s));
}
}
而使用類(lèi)名引用成員方法在某些使用規(guī)則上與我們最開(kāi)始的定義不同:
1.被引用方法的形參必須和抽象方法的第二個(gè)形參到最后一個(gè)形參保持一致,返回值需要保持一致。
抽象方法形參詳解:
第一個(gè)參數(shù):表示被引用方法的調(diào)用者,決定了可以引用哪些類(lèi)中的方法? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 在stream流當(dāng)中,第一個(gè)參數(shù)一般都表示流里面的每一個(gè)數(shù)據(jù)。? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 假設(shè)現(xiàn)在流里面的數(shù)據(jù)是字符串,那么使用這種方式進(jìn)行方法引用的時(shí)候? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 只能使用String這給類(lèi)中的方法。
第二個(gè)參數(shù)到最后一個(gè)參數(shù):跟被引用方法的形參保持一致,如果沒(méi)有第二個(gè)參數(shù)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?那么說(shuō)明被引用的方法需要是無(wú)參的成員方法?
總而言之:使用類(lèi)名引用成員方法的時(shí)候,并不是所有的類(lèi)名都可以使用,只可以使用抽象方法中第一個(gè)參數(shù)對(duì)應(yīng)的類(lèi)型。
而這也就是這種操作的局限性,它限制了我們可以使用方法的種類(lèi)!
5.引用數(shù)組的構(gòu)造方法:
? ? ? ? 格式:數(shù)據(jù)類(lèi)型::new?
? ? ? ? 范例:int [] new
? ? ? ? 細(xì)節(jié):數(shù)組的類(lèi)型需要和流中的數(shù)組類(lèi)型保持一致。
public class test09 {
public static void main(String[] args) {
//1.創(chuàng)建集合并添加元素
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list,1,2,3,4,5,6,7,8,9);
//2.收集到數(shù)組中
//匿名內(nèi)部類(lèi)
Integer[] arr= list.stream().toArray(new IntFunction<Integer[]>() {
@Override
public Integer[] apply(int value) {
return new Integer[value];
}
});
for (Integer integer : arr) {
System.out.println(integer);
}
//方法引用
Integer[] array = list.stream().toArray(Integer[]::new);
for (Integer integer : array) {
System.out.println(integer);
}
}
}
方法引用的優(yōu)點(diǎn):
方法引用(Method Reference)是Java中函數(shù)式編程的一項(xiàng)重要特性,它允許我們通過(guò)方法的名稱(chēng)來(lái)引用一個(gè)已經(jīng)存在的方法,可以看作是Lambda表達(dá)式的簡(jiǎn)化形式。方法引用的優(yōu)點(diǎn)包括:
1. 簡(jiǎn)潔性:方法引用能夠?qū)⒎爆嵉腖ambda表達(dá)式進(jìn)一步簡(jiǎn)化,使代碼更加簡(jiǎn)潔、直觀。通過(guò)引用現(xiàn)有的方法,避免了再次編寫(xiě)大量的重復(fù)代碼。
2. 可讀性:方法引用能夠提高代碼的可讀性和可理解性。通過(guò)使用已有方法的名稱(chēng),可以更直觀地表示代碼的意圖和邏輯。
3. 代碼復(fù)用:方法引用使得代碼重用更加方便。可以將已存在的、已經(jīng)實(shí)現(xiàn)的方法作為引用直接傳遞,從而減少了重復(fù)的方法定義和實(shí)現(xiàn)。
4. 維護(hù)性和一致性:使用方法引用可以使代碼更具有一致性和易于維護(hù)。當(dāng)需要修改方法邏輯時(shí),只需要修改被引用的方法,而無(wú)需修改引用該方法的所有地方。
5. 高效性:方法引用本質(zhì)上是通過(guò)對(duì)已經(jīng)存在的方法進(jìn)行復(fù)用來(lái)實(shí)現(xiàn)的,因此在執(zhí)行效率上可能會(huì)更高一些。
需要注意的是,方法引用并不是適用于所有場(chǎng)景,它有一些使用限制,比如需要滿(mǎn)足函數(shù)式接口的要求,被引用的方法與函數(shù)式接口的抽象方法有著相同的參數(shù)列表和返回類(lèi)型等。
總結(jié):
? ? ? ? 方法引用的出現(xiàn),進(jìn)一步優(yōu)化了lambda表達(dá)式的代碼邏輯,優(yōu)化了我們代碼的效率,是一個(gè)不錯(cuò)的武器,用來(lái)提高我們代碼的復(fù)用性,一致性和高效性,我們要掌握好方法引用這一好武器。
如果我的內(nèi)容對(duì)你有幫助,請(qǐng)點(diǎn)贊,評(píng)論,收藏。創(chuàng)作不易,大家的支持就是我堅(jiān)持下去的動(dòng)力!文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-609697.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-609697.html
到了這里,關(guān)于【從零開(kāi)始學(xué)習(xí)JAVA | 第三十篇】方法引用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!