1. 程式人生 > 程式設計 >Java8方法引用及構造方法引用原理例項解析

Java8方法引用及構造方法引用原理例項解析

如果不熟悉Java8新特性的小夥伴,初次看到函式式介面寫出的程式碼可能會是一種懵逼的狀態,我是誰,我在哪,我可能學了假的Java,(・∀・(・∀・(・∀・*),但是語言都是在進步的,就好比面向物件的語言Java也可以寫出優雅的函式式呼叫,學習的過程並不複雜,當你學會了Java8中函數語言程式設計的新特性,你一定會對他愛不釋手的。下面介紹一下基於Lambda表示式簡寫的兩種引用。避免再次看到這種程式碼時的尷尬😅。

方法引用

方法引用,一般包含下面三種寫法,傳統的寫法我們可能都是通過物件.去呼叫例項方法或使用類.呼叫靜態方法,但是學完方法引用後,就可以可以使用這三種方式去呼叫方法,但是要符合一定的規則。

物件::例項方法

/**
 * 物件呼叫例項方法
 */
public static void objMethod(){
  List<Integer> list = new ArrayList<> ();
  list.add(1);
  list.add(2);
  list.add(3);

  list.forEach((i)->{
    PrintStream out = System.out;
    Consumer<Integer> consumer = out::println;
    consumer.accept(i);
  });
  list.forEach(System.out::println);
}

最常用的System.out.println

類::例項方法

/**
 * 判斷兩個字串是否相同
 *
 * @param str1
 * @param str2
 * @return
 */
public static boolean isEqual(String str1,String str2) {
  BiPredicate<String,String> b = (s1,s2)->s1.equals(str2); ①
  BiPredicate<String,String> bp = String::equals;
  return bp.test(str1,str2);
}

類::靜態方法

/**
 * 比較大小
 * @param x
 * @param y
 * @return
 */
public static boolean compareValue(int x,int y){
  Comparator<Integer> compare = Integer::compare; ②
  return compare.compare(x,y) > 0;
}

其實不管是哪一種呼叫方式都是有規律可循的,這裡總結一下在使用Lambda表示式的過程中符合什麼樣的規則才可以使用方法引用的模式去寫。

Lambda體中呼叫方法的引數列表與返回值型別,要與函式式介面中抽象方法的函式列表和返回值型別保持一致 Integer::compare ②

Lambda引數列表中的第一引數是例項方法的呼叫者,而第二個引數是例項方法的引數時 可以使用ClassName::method ①
構造方法引用#

簡稱花式new物件,一個簡單的new物件也要寫的高階、大氣、上檔次😄,既可以掌握新知識,又可以ZB,趕緊學習吧。

ClassName::new

資源類:

public class Apple {
  private String color;
  private double weight;

  public Apple(){

  }
  public Apple(String color) {
    this.color = color;
  }
  public Apple(double weight) {
    this.weight = weight;
  }
  public Apple(String color,double weight) {
    this.color = color;
    this.weight = weight;
  }
  public String getColor() {
    return color;
  }
  public void setColor(String color) {
    this.color = color;
  }
  public double getWeight() {
    return weight;
  }
  public void setWeight(double weight) {
    this.weight = weight;
  }
  @Override
  public String toString() {
    return "Apple{" +
        "color='" + color + '\'' +
        ",weight=" + weight +
        '}';
  }
}

測試程式碼:

public static void main(String[] args) {
  //無參構造
  //Supplier<Apple> supplier = () -> new Apple(); Lambda表示式寫法
  Supplier<Apple> supplier = Apple::new;
  Apple apple = supplier.get();
  System.out.println("NoArgsConstructor: "+apple);

  //有參構造
  //Function<Double,Apple> function = (x) -> new Apple(x);  Lambda表示式寫法
  // 構造引用
  Function<Double,Apple> function = Apple::new;
  Apple apply = function.apply(1.0);
  System.out.println("OneArgsConstructor: "+apply);

  BiFunction<String,Double,Apple> bf = Apple::new;
  Apple bi = bf.apply("Red",2.0);
  System.out.println("TwoArgsConstructor: "+bi);
}

輸出結果:

NoArgsConstructor: Apple{color='null',weight=0.0}
OneArgsConstructor: Apple{color='null',weight=1.0}
TwoArgsConstructor: Apple{color='Red',weight=2.0}

當構造方法無參時使用Supplier,有一個引數時使用Function,兩個引數時使用BiFunction。這裡很容易得出一個規律,當使用構造方法引用時,函式式介面的引數列表需要和構造方法的引數列表保持一致。

我們也可以用這些函式式介面改寫傳統的建立陣列的方式,初始化一個指定長度的陣列,比如

Function<Integer,String[]> fun = String[]::new;
String[] strArr = fun.apply(10);

也可以這樣寫:

public static <T> T[] initArray(int num,Function<Integer,T[]> function){
  return function.apply(num);
}

呼叫:

Copy
Apple[] strings = initArray(10,x -> new Apple[x]);
System.out.println(strings.length);

疑惑

根據傳入的引數返回指定的物件陣列引用,不過這樣還不如直接建立。不知道讀者有沒有考慮這裡為什麼不可以用一個泛型來new,那樣就可以建立一個通用陣列引用,但是Java中的泛型是偽泛型,在編譯器就會進行泛型擦除,所以不能通過new關鍵字來建立一個泛型物件,具體內容可以在查閱其他資料瞭解泛型以及泛型擦除的原理,這裡不做深究。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。