1. 程式人生 > >基礎之Lambda和Stream的邂逅

基礎之Lambda和Stream的邂逅

show me the code and take to me,做的出來更要說的明白
GitHub專案JavaHouse同步收錄
喜歡就點個讚唄! 你的支援是我分享的動力!

引入

是否有遇到看不懂身邊同事程式碼的情況,是否有被面試官問到 Java 新特性不懂的情況。我掐指一算你大概是遇到的了 Lambda 表示式 和 Stream 流。為了解決上述情況,我特地獻上一份關於 Lambda 和 Stream 的指南,以解燃煤之急。

Lambda

普通呼叫

首先我們先看第一個例子。


@Test
public void test(){
        test1(1);
    }

private void test1(int a){
    System.out.println(a);
}

執行Test,輸出結果

1

相信這裡大家都很清楚,我不需要多廢話!

內部類呼叫

那我們在來看看第二個例子

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);
        }
    });
}

執行Test,輸出結果

1

這裡的話我將參變成了一個介面,使用了內部類。大家是不是覺得這種形式的程式碼不容易看清楚,一個引數竟然放了這麼多東西,真是讓人頭大啊。所以我們有了 Lambda 表示式。

Lambda 重構

我們使用 Lambda 表示式重寫上面程式碼。得到下面新程式碼:

public interface IPerson {
    void personMethod();
}

private void test2(IPerson person){
        person.personMethod();
    }

@Test
public void test2(){
    test2(() -> System.out.println(1));
}

執行Test,輸出結果

1

這樣的程式碼是不是比使用內部類程式碼優雅了很多,看起來舒服極了,關鍵程式碼也少了。這就是 Lambda 表示式的魅力。

Lambda 呼叫

好了,經過上面的層層遞進的例子,我們引出了 Lambda 表示式。現在我們開始瞭解 Lambda 表示式的語法。

語法:

-> 

是的,他的呼叫語法就是一個箭頭。當然這樣說的話我也不太信。其實還沒說完。

當我們的方法沒有引數的時候,沒有返回,他需要保留括號,形式如下:

() -> System.out.println(1);

當有一個引數的時候,沒有返回,小括號可以去掉,形式如下

a -> System.out.println(a)

當有多個引數的時候以及方法裡面的語法多餘一行的時候,沒有返回,,形式如下:

(a, b) -> {
            System.out.println(a);
            System.out.println(b);
        }

上面例子都是沒有返回的,那麼有返回又是怎樣的呢?形式如下:

a -> {
            System.out.println(a);
            return a;
        }

是的,那就加一下返回啊。

函式式介面

其實上面都是展示如果去呼叫,不知道你們是否發現後者感覺到,他沒有方法名就去呼叫了,是不是接受不了。這是正常情況。因為我們呼叫的接口裡面這有一個方法,所以我們只需要一個 ->就可以呼叫到接口裡面方法。

所以我們如果想自己寫一個 Lambda 的話。只需要在接口裡面寫一個抽象方法即可。舉了例子:

public interface IPerson {
    int personMethod(int a);
}

當然我建議加一個註解@FunctionalInterface,形式如下:

@FunctionalInterface
public interface IPerson {
    int personMethod(int a);
}

這樣就是限制接口裡面只能有一個抽象方法了。這個就叫函式式介面。當我們再繼續往裡面加的話,就會報錯了:

其實大多數情況下,我們不需要自己寫函式式介面。因為 Java 已經內建了四種常見的函式式介面。

這四個介面需要一般與 Stream 一起使用。

Stream

普通迭代

我們直接看程式碼,一個普通的迭代例子

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);
    }
}

執行Test,輸出結果

5

在 Java8 之前,我們統計 list 的大小是上面的形式。

Stream 重構

現在我們用 Stream 重構上面的程式碼

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);
    }
}

執行Test,輸出結果

5

瞬間感覺程式碼清爽了很多,變得優雅了,關鍵程式碼也少了。這就是 Stream 的魅力。

經過上面的例子,我們可以感覺到 Stream 可以代替 for 迴圈,進行特定操作。注意這裡是特定的操作,因為 Stream 接口裡面只有只封了幾個方法。

collect()

collect() 方法可以將 Stream 變成 List等集合形式。

我們看一個例子:

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 函式介面一起使用。

不想看文字,還有圖片

該方法可以過濾出特定元素並且返回原來的型別。舉一個例子

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));
    }
}

執行Test,輸出結果

[[4, 5]]

map()

map() 方法與 Function 函式介面一起使用。

不想看文字,還有圖片

該方法可以將原來的集合進行修改,包括返回型別,然後返回一個新的集合。舉一個例子

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));
    }
}

執行Test,輸出結果

[[1, 1, 1, 1, 1, 1]]

我們可以看到兩種情況 Integer -> Integer 以及 Integer -> Boolean

注意我們不能操作同一個 stream 兩次,不然會報錯,有興趣可以試試。

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));
    }
}

執行Test,輸出結果

[[1, 2, 3, 4, 5]]

關注微信公眾號,隨時移動端閱讀