Lambda

是否有遇到看不懂身邊同事代碼的情況,是否有被面試官問(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ò)了:

image.png

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

image.png

這四個(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ù)接口一起使用。

image.png

不想看文字,還有圖片

image.png

該方法可以過(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ù)接口一起使用。

image.png

不想看文字,還有圖片

image.png

該方法可以將原來(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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容