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