方法參考

Java 8中的方法參考

介紹

到目前為止,添加到Java中最甜的語(yǔ)法糖肯定是Lambda Expressions。

Java是一種冗長(zhǎng)的語(yǔ)言,會(huì)妨礙生產(chǎn)率和可讀性。減少樣板代碼和重復(fù)性代碼一直是Java開發(fā)人員的熱門任務(wù),并且通常追求簡(jiǎn)潔,可讀,簡(jiǎn)潔的代碼。

對(duì)于一些常見任務(wù),Lambda Expressions消除了鍵入繁瑣的樣板代碼的需要,它允許開發(fā)人員在不屬于類的情況下調(diào)用它們并將它們像對(duì)象一樣傳遞。

這些表達(dá)式在Java Streams API和Spring的WebFlux框架中主要用于創(chuàng)建反應(yīng)性,動(dòng)態(tài)應(yīng)用程序。

Java 8中另一個(gè)真正有用的功能是方法引用,它使Lambda Expressions更加簡(jiǎn)潔明了,方法是:在使用Lambda Expression僅用于調(diào)用a時(shí),使用方法名稱調(diào)用(引用)方法。方法。

方法參考

方法引用實(shí)質(zhì)上是縮短的Lambda表達(dá)式,用于調(diào)用方法。

它們包括兩個(gè)部分:

Class::method;

常見的示例是打印出說結(jié)果,例如訂閱發(fā)布者服務(wù)或Java Stream:

someCodeChain.subscribe(System.out::println);

讓我們看一下命令式代碼的示例,然后我們將通過Lambda表達(dá)式轉(zhuǎn)向功能代碼,最后通過方法引用進(jìn)行縮短。

我們將做一個(gè)簡(jiǎn)單的類:

public class Employee {
    private int id;
    private String name;
    private int wage;
    private String position;

    // Constructor, getters and setters

    @Override
    public String toString() {
        return "Name: " + name + ", Wage: " + wage + ", Position: " + position;
    }

    public int compareTo(Employee employee) {
        if (this.wage <= employee.wage) {
            return 1;
        } else {
            return -1;
        }
    }
}

如果我們將該類形成一個(gè)集合,例如ArrayList,我們將無法使用實(shí)用程序方法對(duì)其進(jìn)行排序,.sort()因?yàn)樗鼪]有實(shí)現(xiàn)Comparable接口。

我們可以做的是new Comparator在調(diào)用.sort()方法時(shí)為這些對(duì)象定義一個(gè):

Employee emp1 = new Employee(1, "David", 1200, "Developer");
Employee emp2 = new Employee(2, "Tim", 1500, "Developer");
Employee emp3 = new Employee(3, "Martha", 1300, "Developer");

ArrayList<Employee> employeeList = new ArrayList<>();
employeeList.add(emp1);
employeeList.add(emp2);
employeeList.add(emp3);

Collections.sort(employeeList, new Comparator<Employee>() {
    public int compare(Employee emp1, Employee emp2) {
        return emp1.compareTo(emp2);
    }
});

System.out.println(employeeList);

運(yùn)行此代碼將產(chǎn)生:

[Name: Tim, Wage: 1500, Position: Developer, Name: Martha, Wage: 1300, Position: Developer, Name: David, Wage: 1200, Position: Developer]

在此,匿名類(Comparator)正在定義比較條件。通過使用Lambda表達(dá)式,我們可以使其更簡(jiǎn)單,更短:

Collections.sort(employeeList, (e1, e2) -> e1.compareTo(e2));

運(yùn)行這段代碼將產(chǎn)生:

[Name: Tim, Wage: 1500, Position: Developer, Name: Martha, Wage: 1300, Position: Developer, Name: David, Wage: 1200, Position: Developer]

再說一次,由于我們對(duì)Lambda表達(dá)式所做的全部工作都稱為一個(gè)方法,因此我們只能引用該方法:

Collections.sort(employeeList, Employee::compareTo);

這還將產(chǎn)生:

[Name: Tim, Wage: 1500, Position: Developer, Name: Martha, Wage: 1300, Position: Developer, Name: David, Wage: 1200, Position: Developer]

方法參考類型

方法引用可以在兩種不同的情況下使用:

  • 靜態(tài)方法: Class::staticMethodName
  • 特定對(duì)象的實(shí)例方法: object::instanceMethodName
  • 仲裁對(duì)象的實(shí)例方法: Class::methodName
  • 構(gòu)造函數(shù)參考: Class::new

讓我們通過一些簡(jiǎn)單的示例來研究所有這些類型。

靜態(tài)方法參考

您可以static通過簡(jiǎn)單地用方法名稱調(diào)用其包含類來引用類的任何方法。

讓我們用static方法定義一個(gè)類,然后從另一個(gè)類中引用它:

public class ClassA {
    public static void raiseToThePowerOfTwo(double num) {
        double result = Math.pow(num, 2);
        System.out.println(result);
    }
}

現(xiàn)在,從另一個(gè)類中,讓我們使用static實(shí)用程序方法:

public class ClassB {
    public static void main(String[] args) {
        List<Double> integerList = new ArrayList<>();
        integerList.add(new Double(5));
        integerList.add(new Double(2));
        integerList.add(new Double(6));
        integerList.add(new Double(1));
        integerList.add(new Double(8));
        integerList.add(new Double(9));

        integerList.forEach(ClassA::raiseToThePowerOfTwo);
    }
}

運(yùn)行這段代碼將產(chǎn)生:

25.0
4.0
36.0
1.0
64.0
81.0

有許多Java類提供static可以在此處使用的實(shí)用程序方法。在我們的示例中,我們使用了一種自定義方法,盡管在這種情況下不是一個(gè)非常有用的方法。

特定對(duì)象的實(shí)例方法

通過使用對(duì)象的引用變量引用該方法,可以從特定的實(shí)例化對(duì)象調(diào)用方法。

訂閱我們的新聞
在收件箱中獲取臨時(shí)教程,指南和作業(yè)。從來沒有垃圾郵件。隨時(shí)退訂。

訂閱電子報(bào)
訂閱

這通常通過自定義比較器進(jìn)行說明。我們將使用Employee之前的相同類和相同的列表來突出顯示兩者之間的區(qū)別:

public class Employee {
    private int id;
    private String name;
    private int wage;
    private String position;

    // Constructor, getters and setters

    @Override
    public String toString() {
        return "Name: " + name + ", Wage: " + wage + ", Position: " + position;
    }

    public int compareTo(Employee employee) {
        if (this.wage <= employee.wage) {
            return 1;
        } else {
            return -1;
        }
    }
}

現(xiàn)在,讓我們定義一個(gè)CustomComparator

public class CustomComparator {
    public int compareEntities(Employee emp1, Employee emp2) {
        return emp1.compareTo(emp2);
    }
}

最后,讓我們填充一個(gè)列表并對(duì)其進(jìn)行排序:

Employee emp1 = new Employee(1, "David", 1200, "Developer");
Employee emp2 = new Employee(2, "Tim", 1500, "Developer");
Employee emp3 = new Employee(3, "Martha", 1300, "Developer");

ArrayList<Employee> employeeList = new ArrayList<>();
employeeList.add(emp1);
employeeList.add(emp2);
employeeList.add(emp3);

// Initializing our CustomComparator
CustomComparator customComparator = new CustomComparator();

// Instead of making a call to an arbitrary Employee
// we're now providing an instance and its method
Collections.sort(employeeList, customComparator::compareEntities);

System.out.println(employeeList);

運(yùn)行此代碼還將產(chǎn)生:

[Name: Tim, Wage: 1500, Position: Developer, Name: Martha, Wage: 1300, Position: Developer, Name: David, Wage: 1200, Position: Developer]

主要區(qū)別在于,通過添加了另一層,CustomComparator我們可以添加更多功能進(jìn)行比較并將其從類本身中刪除。諸如此類的類Employee不應(yīng)承受復(fù)雜的比較邏輯的負(fù)擔(dān),這將導(dǎo)致更清晰,更易讀的代碼。

另一方面,有時(shí)我們不希望定義自定義比較器,而引入一個(gè)比較器簡(jiǎn)直太麻煩了。在這種情況下,我們將從特定類型的任意對(duì)象中調(diào)用方法,如下一節(jié)所示。

任意對(duì)象的實(shí)例方法

當(dāng)我們將命令式方法通過Lambda Expressions分解為功能性方法時(shí),該示例已在本文開頭顯示。

不過,從良好的角度來看,由于這種方法的使用頻率很高,因此讓我們來看另一個(gè)示例:

List<Integer> integerList = new ArrayList<>();
integerList.add(new Integer(5));
integerList.add(new Integer(2));
integerList.add(new Integer(6));
integerList.add(new Integer(1));
integerList.add(new Integer(8));
integerList.add(new Integer(9));

// Referencing the non-static compareTo method from the Integer class
Collections.sort(integerList, Integer::compareTo);

// Referencing static method
integerList.forEach(System.out::print);

運(yùn)行這段代碼將產(chǎn)生:

125689

雖然這可能看起來像它一樣的靜態(tài)方法的調(diào)用,它不是。這等效于調(diào)用Lambda表達(dá)式:

Collections.sort(integerList, (Integer a, Integer b) -> a.compareTo(b));

在這里,區(qū)別更加明顯。如果我們要調(diào)用一個(gè)static方法,它將看起來像:

Collections.sort(integerList, (Integer a, Integer b) -> SomeClass.compare(a, b));

引用構(gòu)造函數(shù)

您可以像引用static方法一樣引用類的構(gòu)造函數(shù)。

您可以使用對(duì)構(gòu)造函數(shù)的引用,而不是經(jīng)典的類實(shí)例化:

// Classic instantiation
Employee employee = new Employee();

// Constructor reference
Employee employee2 = Employe::new;

根據(jù)上下文,如果存在多個(gè)構(gòu)造函數(shù),則在引用時(shí)將使用足夠的構(gòu)造函數(shù):

Stream<Employee> stream = names.stream().map(Employee::new);

由于名稱流,如果存在Employee(String name)構(gòu)造函數(shù),則將使用它。

可以使用構(gòu)造函數(shù)引用的另一種方式是,當(dāng)您想要將流映射到數(shù)組中時(shí),同時(shí)保留特定的類型。如果要簡(jiǎn)單地映射它,然后調(diào)用toArray(),則會(huì)得到Objects數(shù)組,而不是您的特定類型。

如果我們嘗試過,請(qǐng)說:

Employee[] employeeArray = employeeList.toArray();

當(dāng)然,由于.toArray()返回Objects數(shù)組,因此會(huì)遇到編譯器錯(cuò)誤。投射它也無濟(jì)于事:

Employee[] employeeArray = (Employee[]) employeeList.toArray();

但是這次,它將是運(yùn)行時(shí)異常- ClassCastException。

我們可以通過以下方法避免這種情況:

// Making a list of employees
List<String> employeeList = Arrays.asList("David", "Scott");

// Mapping a list to Employee objects and returning them as an array
Employee[] employeeArray = employeeList.stream().map(Employee::new).toArray(Employee[]::new);

// Iterating through the array and printing information
for (int i = 0; i < employeeArray.length; i++) {
    System.out.println(employeeArray[i].toString());
}

這樣,我們得到輸出:

Name: David, Wage: 0, Position: null
Name: Scott, Wage: 0, Position: null

結(jié)論

方法引用是Lambda表達(dá)式的一種,用于在調(diào)用中簡(jiǎn)單地引用方法。使用它們,編寫代碼可以更加簡(jiǎn)潔和可讀。

Lambda Expressions向Java開發(fā)人員介紹了一種更具功能性的編程方法,該方法允許他們避免為簡(jiǎn)單操作編寫冗長(zhǎng)的代碼。

發(fā)布于 2021-01-09 16:16

轉(zhuǎn)自 何鵬

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容