Lambda 是一個匿名函數,可以把 Lambda表達式理解爲是一段可以傳遞的代碼(將代碼像數據一樣進行傳遞)。使用Lambda可以寫出更簡潔、更靈活的代碼,作爲一種更緊湊的代碼風格,使Java的語言表達能力得到了提升。下面介紹幾個特點:
1.替代匿名內部類
毫無疑問,lambda表達式用得最多的場合就是替代匿名內部類,而實現Runnable接口是匿名內部類的經典例子。lambda表達式的功能相當強大,用()->就可以代替整個匿名內部類!請看代碼:
如果使用匿名內部類:
@Test
public void oldRunable() {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Test old!");
}
}).start();
}
而如果使用lambda表達式:
@Test
public void runable() {
new Thread(() -> System.out.println("Test new!")).start();
}
最後的輸出:
Test old!
Test new!
清晰明瞭,重點突出,用極少的代碼完成了之前一個類的職責。
2.使用lambda表達式對集合進行迭代
請看迭代遍歷的對比:
@Test
public void iterTest() {
List<String> languages = Arrays.asList("java","scala","python");
//before java8
for(String each:languages) {
System.out.println(each);
}
//after java8
languages.forEach(x -> System.out.println(x));
languages.forEach(System.out::println);
}
如果熟悉scala的同學,肯定對forEach不陌生。它可以迭代集合中所有的對象,並且將lambda表達式帶入其中。
languages.forEach(System.out::println);
這一行看起來有點像c++裏面作用域解析的寫法,在這裏也是可以的。
3.用lambda表達式實現map
java8同樣支持函數式編程。請看示例代碼,通過map方法將cost增加了0,05倍的大小然後輸出。:
@Test
public void mapTest() {
List<Double> cost = Arrays.asList(10.0, 20.0,30.0);
cost.stream().map(x -> x + x*0.05).forEach(x -> System.out.println(x));
}
最後的輸出結果:
10.5
21.0
31.5
map函數可以說是函數式編程裏最重要的一個方法了,其作用是將一個對象變換爲另外一個。
4.用lambda表達式實現map與reduce
reduce與map一樣,也是函數式編程裏的重要方法之一。map的作用是將一個對象變爲另外一個,而reduce則是將所有值合併爲一個,請看:
@Test
public void mapReduceTest() {
List<Double> cost = Arrays.asList(10.0, 20.0,30.0);
double allCost = cost.stream().map(x -> x+x*0.05).reduce((sum,x) -> sum + x).get();
System.out.println(allCost);
}
最終的結果爲:
63.0
如果我們用for循環來做這件事情:
@Test
public void sumTest() {
List<Double> cost = Arrays.asList(10.0, 20.0,30.0);
double sum = 0;
for(double each:cost) {
each += each * 0.05;
sum += each;
}
System.out.println(sum);
}
相信用map+reduce+lambda表達式的寫法高出不止一個level。
5.filter操作
filter也是我們經常使用的一個操作。在操作集合的時候,經常需要從原始的集合中過濾掉一部分元素。
@Test
public void filterTest() {
List<Double> cost = Arrays.asList(10.0, 20.0,30.0,40.0);
List<Double> filteredCost = cost.stream().filter(x -> x > 25.0).collect(Collectors.toList());
filteredCost.forEach(x -> System.out.println(x));
}
最後的結果:
30.0
40.0
將java寫出了python或者scala的感覺有沒有!是不是帥到爆!
6.與函數式接口Predicate配合
除了在語言層面支持函數式編程風格,Java 8也添加了一個包,叫做 java.util.function。它包含了很多類,用來支持Java的函數式編程。其中一個便是Predicate,使用 java.util.function.Predicate 函數式接口以及lambda表達式,可以向API方法添加邏輯,用更少的代碼支持更多的動態行爲。Predicate接口非常適用於做過濾。
public static void filterTest(List<String> languages, Predicate<String> condition) {
languages.stream().filter(x -> condition.test(x)).forEach(x -> System.out.println(x + " "));
}
public static void main(String[] args) {
List<String> languages = Arrays.asList("Java","Python","scala","Shell","R");
System.out.println("Language starts with J: ");
filterTest(languages,x -> x.startsWith("J"));
System.out.println("\nLanguage ends with a: ");
filterTest(languages,x -> x.endsWith("a"));
System.out.println("\nAll languages: ");
filterTest(languages,x -> true);
System.out.println("\nNo languages: ");
filterTest(languages,x -> false);
System.out.println("\nLanguage length bigger three: ");
filterTest(languages,x -> x.length() > 4);
}
最後的輸出結果:
Language starts with J:
Java
Language ends with a:
Java
scala
All languages:
Java
Python
scala
Shell
R
No languages:
Language length bigger three:
Python
scala
Shell
可以看到,Stream API的過濾方法也接受一個Predicate,這意味着可以將我們定製的 filter() 方法替換成寫在裏面的內聯代碼,這也是lambda表達式的魔力!
參考: