JDK8新特性:使用Method References實現方法複用,簡化lambda運算式__方法引用

來源:互聯網
上載者:User

之前的文章已經介紹了函數式介面與lambda運算式,這篇文章主要學習下方法引用。使用方法引用,可以減少lambda運算式的書寫,在Stream API中很常用。

一段代碼對比下lambda與靜態方法引用:

List<Integer> ids = Arrays.asList(1, 2, 5, 4, 3);// 使用lambda運算式Comparator<Integer> comparator1 = (a, b) -> a - b;// 使用靜態方法引用Comparator<Integer> comparator2 = Integer::compare;List<Integer> sorted1 = ids.stream().sorted(comparator1).collect(Collectors.toList());List<Integer> sorted2 = ids.stream().sorted(comparator2).collect(Collectors.toList());System.out.println(ids);// [1, 2, 5, 4, 3]System.out.println(sorted1); // [1, 2, 3, 4, 5]System.out.println(sorted2); // [1, 2, 3, 4, 5]
我們想實現整數list的排序,使用lambda我們還得自己編寫一個Comparator對象(雖然也很簡單),實際上JDK類庫已經提供了類似的實現,我們通過Integer::compare就可以引用已經存在的方法。


JDK8中的方法引用分成4類:靜態方法引用、執行個體方法引用、構造方法引用、以靜態方式引用執行個體方法。


(1).靜態方法引用

格式:ClassName::staticMethodName,比如:

String::valueOf   等價於lambda運算式 (s)  -> String.valueOf(s)

Math::pow          等價於lambda運算式 (x, y) -> Math.pow(x, y)

@FunctionalInterfacepublic interface MyInterface {    public double calculate(double a, double b);}
// 靜態方法引用powMyInterface ins1 = Math::pow;System.out.println(ins1.calculate(2, 4) == 16);// 靜態方法引用maxMyInterface ins2 = Math::max;System.out.println(ins2.calculate(2, 4) == 4);


可以看到我們定義的函數式介面MyInterface,必須要與其引用的靜態方法,具有同樣的傳回值和入參


(2).執行個體方法引用

格式:instanceReference::methodName,比如:

str::toString  等價於lambda運算式 ()  ->  str.toString()

str::concat    等價於lambda運算式 (another)  ->  str.concat(another)

@FunctionalInterfacepublic interface MyInterface {    // 與String.concat()同樣的入參和傳回值    public String transform(String input);}
String content = "abc";// 引用String類的執行個體方法MyInterface ins1 = content::concat;System.out.println(ins1.transform("def"));// abcdef
可以看到我們實現的效果:定義一個函數式介面,它的方法與原始的concat擁有同樣的參數類型和傳回值,相當於是給concat重新命名。


(3).構造方法引用

格式:ClassName::new,如果ClassName有多個建構函式,那麼JDK會自動根據函數式介面的方法聲明來決定到底使用哪兒一個建構函式。

public class Target {    public int attr = 0;    public Target() {    }    public Target(int b) {        this.attr = b;    }}
@FunctionalInterfacepublic interface MyInterface {    public Target create(int value);}
MyInterface ins = Target::new;Target t = ins.create(1); // 可以自動推斷使用的建構函式System.out.println(t.attr);// 1



數組的建構函式與之類似,不過是建構函式有個參數(數組長度)。

@FunctionalInterfacepublic interface MyInterface {    public int[] create(int length);}
MyInterface ins = int[]::new;int[] array = ins.create(10);System.out.println(array.length);// 10



(4).以靜態方式引用執行個體方法

不知道叫什麼名字才合適,姑且這麼叫吧。靜態方法引用和類型上的執行個體方法引用擁有一樣的文法,編譯器會根據實際情況做出決定。

格式:ClassName::instanceMethod,比如:

String::toString  等價於lambda運算式  (String s) -> s.toString()

Lambda的第一個參數會成為調用執行個體方法的對象

public class Target {    private int attr = 0;    public Target(int attr) {        this.attr = attr;    }    public int compareTo(Target another) {        return this.attr - another.attr;    }    public static int compare(Target one, Target another) {        return one.attr - another.attr;    }}
// 函數式介面:實現Target對象比較@FunctionalInterfacepublic interface MyInterface {    public int compare(Target one, Target another);}
Target target1 = new Target(10);Target target2 = new Target(100);// 引用執行個體方法MyInterface ins1 = Target::compare;System.out.println(ins1.compare(target1, target2));// -90// 引用靜態方法MyInterface ins2 = Target::compare;System.out.println(ins2.compare(target1, target2));// -90


最後給個例子,看下方法引用的威力:

public class Person {    private String name;        private Date birthday;    public Person(String name, Date birthday) {        this.name = name;        this.birthday = birthday;    }    public Date getBirthday() {        return birthday;    }    public void setBirthday(Date birthday) {        this.birthday = birthday;    }    @Override    public String toString() {        return "Person{" +                "name='" + name + '\'' +                ", birthday=" + birthday +                '}';    }}
List<Person> persons = new ArrayList<>();persons.add(new Person("c", "2017-01-01"));persons.add(new Person("b", "2016-01-01"));persons.add(new Person("a", "2015-01-01"));

現在我們想對persons集合按照name排序:
// 方式1Collections.sort(persons, new Comparator<Person>() {@Overridepublic int compare(Person o1, Person o2) {return o1.getName().compareTo(o2.getName());}});System.out.println(persons);
方式一是比較傳統的做法,自己實現一個Comparator比較子。


// 方式2Collections.sort(persons, (o1, o2)->o1.getName().compareTo(o2.getName()));System.out.println(persons);
方式2使用了lambda運算式


// 方式3Collections.sort(persons, Comparator.comparing(Person::getName));System.out.println(persons);
方式3使用了方法引用,可以複用比較邏輯,不用自己實現Comparator。


參考文章:https://my.oschina.net/luoyezhuifeng/blog/801343


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.