是否有遇到看不懂身邊同事代碼的情況,是否有被面試官問(wèn)到 Java 新特性不懂的情況。我掐指一算你大概是遇到的了 Lambda 表達(dá)式 和 Stream 流。為了解決上述情況,我特地獻(xiàn)上一份關(guān)于 Lambda 和 Stream 的指南,以解燃煤之急。
Lambda
普通調(diào)用
首先我們先看第一個(gè)例子。
@Test
public void test(){
test1(1);
}
private void test1(int a){
System.out.println(a);
}
運(yùn)行Test,輸出結(jié)果
1
相信這里大家都很清楚,我不需要多廢話!
內(nèi)部類調(diào)用
那我們?cè)趤?lái)看看第二個(gè)例子
public interface IPerson {
void personMethod();
}
private void test2(IPerson person){
person.personMethod();
}
@Test
public void test2(){
test2(new IPerson(){
@Override
public void personMethod() {
System.out.println(1);
}
});
}
運(yùn)行Test,輸出結(jié)果
1
這里的話我將參變成了一個(gè)接口,使用了內(nèi)部類。大家是不是覺(jué)得這種形式的代碼不容易看清楚,一個(gè)參數(shù)竟然放了這么多東西,真是讓人頭大啊。所以我們有了 Lambda 表達(dá)式。
Lambda 重構(gòu)
我們使用 Lambda 表達(dá)式重寫上面代碼。得到下面新代碼:
public interface IPerson {
void personMethod();
}
private void test2(IPerson person){
person.personMethod();
}
@Test
public void test2(){
test2(() -> System.out.println(1));
}
運(yùn)行Test,輸出結(jié)果
1
這樣的代碼是不是比使用內(nèi)部類代碼優(yōu)雅了很多,看起來(lái)舒服極了,關(guān)鍵代碼也少了。這就是 Lambda 表達(dá)式的魅力。
Lambda 調(diào)用
好了,經(jīng)過(guò)上面的層層遞進(jìn)的例子,我們引出了 Lambda 表達(dá)式?,F(xiàn)在我們開(kāi)始了解 Lambda 表達(dá)式的語(yǔ)法。
語(yǔ)法:
->
是的,他的調(diào)用語(yǔ)法就是一個(gè)箭頭。當(dāng)然這樣說(shuō)的話我也不太信。其實(shí)還沒(méi)說(shuō)完。
當(dāng)我們的方法沒(méi)有參數(shù)的時(shí)候,沒(méi)有返回,他需要保留括號(hào),形式如下:
() -> System.out.println(1);
當(dāng)有一個(gè)參數(shù)的時(shí)候,沒(méi)有返回,小括號(hào)可以去掉,形式如下
a -> System.out.println(a)
當(dāng)有多個(gè)參數(shù)的時(shí)候以及方法里面的語(yǔ)法多余一行的時(shí)候,沒(méi)有返回,,形式如下:
(a, b) -> {
System.out.println(a);
System.out.println(b);
}
上面例子都是沒(méi)有返回的,那么有返回又是怎樣的呢?形式如下:
a -> {
System.out.println(a);
return a;
}
是的,那就加一下返回啊。
函數(shù)式接口
其實(shí)上面都是展示如果去調(diào)用,不知道你們是否發(fā)現(xiàn)后者感覺(jué)到,他沒(méi)有方法名就去調(diào)用了,是不是接受不了。這是正常情況。因?yàn)槲覀冋{(diào)用的接口里面這有一個(gè)方法,所以我們只需要一個(gè) ->就可以調(diào)用到接口里面方法。
所以我們?nèi)绻胱约簩懸粋€(gè) Lambda 的話。只需要在接口里面寫一個(gè)抽象方法即可。舉了例子:
public interface IPerson {
int personMethod(int a);
}
當(dāng)然我建議加一個(gè)注解@FunctionalInterface,形式如下:
@FunctionalInterface
public interface IPerson {
int personMethod(int a);
}
這樣就是限制接口里面只能有一個(gè)抽象方法了。這個(gè)就叫函數(shù)式接口。當(dāng)我們?cè)倮^續(xù)往里面加的話,就會(huì)報(bào)錯(cuò)了:

其實(shí)大多數(shù)情況下,我們不需要自己寫函數(shù)式接口。因?yàn)?Java 已經(jīng)內(nèi)置了四種常見(jiàn)的函數(shù)式接口。

這四個(gè)接口需要一般與 Stream 一起使用。
Stream
普通迭代
我們直接看代碼,一個(gè)普通的迭代例子
public class StreamTest {
@Test
public void test2(){
List list = Arrays.asList(1, 2, 3, 4, 5);
int count = 0;
for (Object o : list){
count ++;
}
System.out.println(count);
}
}
運(yùn)行Test,輸出結(jié)果
5
在 Java8 之前,我們統(tǒng)計(jì) list 的大小是上面的形式。
Stream 重構(gòu)
現(xiàn)在我們用 Stream 重構(gòu)上面的代碼
public class StreamTest {
@Test
public void test3(){
List list = Arrays.asList(1, 2, 3, 4, 5);
long count = list.stream().count();
System.out.println(count);
}
}
運(yùn)行Test,輸出結(jié)果
5
瞬間感覺(jué)代碼清爽了很多,變得優(yōu)雅了,關(guān)鍵代碼也少了。這就是 Stream 的魅力。
經(jīng)過(guò)上面的例子,我們可以感覺(jué)到 Stream 可以代替 for 循環(huán),進(jìn)行特定操作。注意這里是特定的操作,因?yàn)?Stream 接口里面只有只封了幾個(gè)方法。
collect()
collect() 方法可以將 Stream 變成 List等集合形式。
我們看一個(gè)例子:
public class StreamTest {
@Test
public void test4(){
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5,1);
List<Integer> collect = stream.collect(Collectors.toList());
}
}
fiter()
fiter() 方法與 Predicate 函數(shù)接口一起使用。

不想看文字,還有圖片

該方法可以過(guò)濾出特定元素并且返回原來(lái)的類型。舉一個(gè)例子
public class StreamTest {
@Test
public void test5(){
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5,1);
List<Integer> collect = stream.filter(a -> a > 3).collect(Collectors.toList());
System.out.println(Arrays.asList(collect));
}
}
運(yùn)行Test,輸出結(jié)果
[[4, 5]]
map()
map() 方法與 Function 函數(shù)接口一起使用。

不想看文字,還有圖片

該方法可以將原來(lái)的集合進(jìn)行修改,包括返回類型,然后返回一個(gè)新的集合。舉一個(gè)例子
public class StreamTest {
@Test
public void test8(){
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5,1);
List<Integer> collect = stream.map(a -> a = 1).collect(Collectors.toList());
// List<Boolean> collect = stream.map(a -> a == 1).collect(Collectors.toList());
System.out.println(Arrays.asList(collect));
}
}
運(yùn)行Test,輸出結(jié)果
[[1, 1, 1, 1, 1, 1]]
我們可以看到兩種情況 Integer -> Integer 以及 Integer -> Boolean
注意我們不能操作同一個(gè) stream 兩次,不然會(huì)報(bào)錯(cuò),有興趣可以試試。
distinct()
該方法意如其字,就是去重。代碼如下
public class StreamTest {
@Test
public void test7(){
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5,1);
List<Integer> collect = stream.distinct().collect(Collectors.toList());
System.out.println(Arrays.asList(collect));
}
}
運(yùn)行Test,輸出結(jié)果
[[1, 2, 3, 4, 5]]
轉(zhuǎn)載自:https://www.zhihu.com/question/20125256/answer/960780342