基礎之Lambda和Stream的邂逅

show me the code and talk to me,作的出來更要說的明白
GitHub項目JavaHouse同步收錄
喜歡就點個讚唄! 你的支持是我分享的動力!java

引入

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

Lambda

普通調用

首先咱們先看第一個例子。github

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

private void test1(int a){
    System.out.println(a);
}
複製代碼

運行Test,輸出結果面試

1
複製代碼

相信這裏你們都很清楚,我不須要多廢話!bash

內部類調用

那咱們在來看看第二個例子微信

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,輸出結果ide

1
複製代碼

這裏的話我將參變成了一個接口,使用了內部類。你們是否是以爲這種形式的代碼不容易看清楚,一個參數居然放了這麼多東西,真是讓人頭大啊。因此咱們有了 Lambda 表達式。函數

Lambda 重構

咱們使用 Lambda 表達式重寫上面代碼。獲得下面新代碼:spa

public interface IPerson {
    void personMethod();
}

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

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

運行Test,輸出結果3d

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]]
複製代碼

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

公衆號.jpg
相關文章
相關標籤/搜索