Java8新特性---Lambda表達式

Lambda表達式

Lambda表達式的本質只是一個語法糖,由編譯器推斷並幫你轉換包裝爲常規的代碼,因此你可以使用更少的代碼來實現同樣的功能。

基本語法:

(parameters -> expression)  
(parameters -> {expression;})

簡單例子:

//僅用三行代碼完成 排序後輸出列表
public static void main(String[] args) {
        List<Integer> integers = Arrays.asList(5, 6, 8, 2, 3, 4, 7, 8, 10);
        Collections.sort(integers, (i1,i2) -> i1.compareTo(i2));
        integers.forEach(i -> System.out.println(i));
    }

爲什麼使用lambda

應用場景如下:根據不同的策略,選出滿足策略條件的蘋果進行分類,而策略經常變更。

public interface MatchInterface<T> {

    public boolean match(T t);

}
public class MatchClient {

    public static <T> boolean match(T t, MatchInterface<T> s) {
        return s.match(t);
    }

    public static void main(String[] args) {
        Apple apple = new Apple("red", 150);

        // 匿名類實現
        match(apple, new MatchInterface<Apple>() {
            public boolean match(Apple apple) {
                return "red".equals(apple.getColor());
            }
        });

        // lambda表達式實現
        match(apple,  tmp -> "red".equals(tmp.getColor()));

        match(apple, (Apple tmp) -> {
            return "red".equals(tmp.getColor());
        });
    }
}

如上代碼所示,即便使用匿名類的形式,比起lambda表達式的實現還是複雜許多。更別說定義實現類。顯然可以看出lambda表達式簡潔的特性。但是相較而言,無法複用也是lambda表達式對比實現類的缺陷。然後lambda本身就是針對這種較少使用的場景,因而這也不成問題。

對比匿名類和lambda表達式,很容易看出:

->左邊部分是接口抽象方法的參數,而右邊是抽象方法的具體實現。

函數式接口

對於一個接口,無論定義了多少個默認方法,只要只定義了一個抽象方法,那麼這個接口就是函數式接口。

lambda表達式使用在函數式接口的參數位置,現在我們再回頭看示例排序迭代輸出代碼:

Collections.sort(integers, (i1,i2) -> i1.compareTo(i2));

public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
}

public int compareTo(Integer anotherInteger) {
        return compare(this.value, anotherInteger.value);
    }

public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }

@FunctionalInterface
public interface Comparator<T> { 
      int compare(T o1, T o2);
}

通過lambda表達式實現Comparator接口,達到排序的目的。

integers.forEach(i -> System.out.println(i));

default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

顯然這也是對列表的每個元素做accept操作。即輸出到控制檯。

使用@FunctionalInterface註解可以提前校驗接口是否是函數式接口

源碼中提供的幾個函數式接口:

  • Predicate:接受泛型T對象,返回boolean
  • Consumer:接受泛型T對象,沒有返回
  • Function:接受泛型T對象,返回R對象

進一步簡潔化

方法引用

如果一個Lambda代表的只是直接調用這個方法,那最好使用名稱來調用。

構造三種方法引用:

  • 指向靜態方法的方法引用

    (args) -> className.staticMethod(args)
    
    className::staticMethod

    示例代碼:

    public class MethodInvokingClient {
    
    public static List<Integer> transformString2Integer(List<String> list, Function<String, Integer> f) {
        List<Integer> nums = new ArrayList<>();
        for (String string : list) {
            nums.add(f.apply(string));
        }
        return nums;
    }
    
    public static void main(String[] args) {
    
        List<String> list = Arrays.asList("1", "3", "5");
    
        transformString2Integer(list, (String s) -> Integer.parseInt(s));
    
        transformString2Integer(list, Integer::parseInt);
    
    }
    }
  • 指向任意類型實例方法的方法引用

    (arg0,rest) -> arg0.instanceMethod(rest)
    
    ClassName::instanceMethod                 //ClassName是arg0的類型

    示例代碼:

    public static List<Integer> calculateStringLength(List<String> list, Function<String, Integer> f) {
        List<Integer> nums = new ArrayList<>();
        for (String string : list) {
            nums.add(f.apply(string));
        }
        nums.forEach(i -> System.out.println(i));
        return nums;
    
    }
    
    public static void main(String[] args) {
    
        List<String> list = Arrays.asList("1", "3", "5");
    
        calculateStringLength(list, s -> s.length());
    
        calculateStringLength(list, String::length);
    
    }
  • 指向現有對象的實例方法的方法引用

    (args) -> anotherInstance.instanceMethod(args)
    
    anotherInstance::instanceMethod

    示例代碼:

    public static int contais(List<String> list, Function<String, Boolean> f){
        int count = 0;
        for (String string : list) {
            if(f.apply(string)){
                count++;
            }
        }
        return count;
    }
    
    public static void main(String[] args) {
    
        List<String> list = Arrays.asList("1", "3", "5");
        List<String> anotherList = Arrays.asList("1", "4", "5");
    
        contais(list, s -> anotherList.contains(s));
    
        contais(list, anotherList::contains);
    
    }

複合lambda

  • 比較器複合

    List<Integer> integers = Arrays.asList(5, 6, 8, 2, 3, 4, 7, 8, 10);
    Comparator<Integer> com = (i1,i2) -> i1.compareTo(i2);
    integers.sort(com.reversed());
  • 謂詞複合

    Apple apple = new Apple("red", 150);
    Predicate<Apple> match = tmp -> "red".equals(tmp.getColor());
    Predicate<Apple> match2 = match.and(tmp -> tmp.getWeight() > 200);
    match2.test(apple);
  • 函數複合

    Function<Integer, Integer> f = x -> x+1;
        Function<Integer, Integer> g = x -> x*2;
        Function<Integer, Integer> h = f.compose(g);
        int r = h.apply(1);
    //結果爲3
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章