1. 程式人生 > >Java Stream函數語言程式設計圖文詳解(二):管道資料處理

Java Stream函數語言程式設計圖文詳解(二):管道資料處理

一、Java Stream管道資料處理操作

在本號之前釋出的文章《Java Stream函數語言程式設計?用過都說好,案例圖文詳解送給你》中,筆者對Java Stream的介紹以及簡單的使用方法給大家做了介紹。在開始本文之前,我們有必要介紹一下這張Java Stream 資料處理過程圖,圖中主要分三個部分:

  • 將陣列、集合類、文字檔案轉換為管道流(圖中的藍色方塊的部分,在本號的上一篇文章中已經給大家介紹過了)
  • Java Stream管道資料處理操作(也就是下圖中中間的虛線內的資料處理操作,本文的主要內容)
  • 管道流處理結果的聚合、累加、計數、轉換為集合類等操作(圖中的綠色方塊部分)

需要注意的是:Java Stream的中間資料處理操作的輸入是一個管道流(Stream),輸出仍然是一個管道流(Stream)。下面我們就來詳細的學習一下!在上一篇文章中,我們給大家講了這樣一個例子:

    List<String> nameStrs = Arrays.asList("Monkey", "Lion", "Giraffe","Lemur");
    
    List<String> list = nameStrs.stream()
            .filter(s -> s.startsWith("L"))
            .map(String::toUpperCase)
            .sorted()
            .collect(toList());
    System.out.println(list);

這個例子完成的功能就是:首先使用stream()函式將陣列轉換為管道流,然後對管道流中的元素進行過濾filter(),只保留L開頭的元素,然後對每一個元素轉換為大寫(map(String::toUpperCase)),然後排序sorted(),最終轉換為List型別。經過處理之後的輸出結果是: [LEMUR, LION].在上面的例子中,filter()、map()、sorted()都屬於中間資料處理操作,下面就給大家講解一下這些函式的詳細用法。

二、filter管道資料過濾

根據筆者的的經驗,filter()是Stream API最有用的操作之一,它可以過濾掉不符合條件的元素。下面的程式碼過濾掉管道中的不是以L開頭的字串元素。處理完成之後,管道中剩下的元素是:[Lion, Lemur]

     Stream<String> startsWithT = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
     .filter(s -> s.startsWith("L"));

如果沒有學過lambda表示式的同學,可能對上面的程式碼感到困惑。其實很簡單,lambda表示式用來表達函式,箭頭左側是引數,箭頭右側是函式體。函式的引數型別和返回值型別,會根據上下文做自動化的判斷,不用你管。上文中的lambda表示式寫成函式是這樣的

    public static boolean filterUpperL(String str){
        return str.startsWith("L");
    }
    
    //.filter(BootLaunchApplicationTests::filterUpperL)

我甚至見過有的人排斥使用lambda表示式,說這種語法使程式碼的可讀性下降。這個怎麼說呢,如果一篇專業期刊中包含英語專業名詞與引用,而讀者恰巧不會英語就不想讀了,我覺得這不是文章的問題,而是讀者的問題。而且lamdba表示式在各種程式語言裡面得到廣泛的使用,提高編碼效率。其實很簡單:箭頭左側是引數,箭頭右側是函式體,你已經學會了!

三、Limit與Skip管道資料擷取

     Stream<String> startsWithT = Stream.of("Monkey", "Lion", "Giraffe", "Lemur").limit(2);
     Stream<String> startsWithT = Stream.of("Monkey", "Lion", "Giraffe", "Lemur").skip(2);
  • limt方法傳入一個整數n,用於擷取管道中的前n個元素。經過管道處理之後的資料是:[Monkey, Lion]。
  • skip方法與limit方法的使用相反,用於跳過前n個元素,擷取從n到末尾的元素。經過管道處理之後的資料是: [Giraffe, Lemur]

四、Distinct元素去重

我們還可以使用distinct方法對管道中的元素去重,涉及到去重就一定涉及到元素之間的比較,distinct方法時呼叫Object的equals方法進行物件的比較的,如果你有自己的比較規則,可以重寫equals方法。

    Stream<String> uniqueAnimals = Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
            .distinct();

上面程式碼去重之後的結果是: ["Monkey", "Lion", "Giraffe", "Lemur"]

五、Sorted排序

預設的情況下,sorted是按照字母的自然順序進行排序。如下程式碼的排序結果是:[Giraffe, Lemur, Lion, Monkey],字數按順序G在L前面,L在M前面。第一位無法區分順序,就比較第二位字母。

    Stream<String> alphabeticOrder = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
            .sorted();

有的時候,我們希望排序的規則能夠自定義,這就需要使用到Comparator。有的朋友這裡可能忘了,可以自行回顧一下java基礎的Comparator和Comparable介面。下面的程式碼是根據字串的長度排序,排序結果是:[Lion, Lemur, Monkey, Giraffe]

    Stream<String> lengthOrder = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
            .sorted(Comparator.comparing(String::length));

六、Map資料轉換處理

map()函式的作用是將管道流中的每一個元素,以某種規則轉換為另外一個元素。下面程式碼處理過的管道中的元素為: [monkey, lion, giraffe, lemur],所有元素的字母全部小寫。

    Stream<String> lowerCase = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
            .map(String::toLowerCase);
    
    //這兩種寫法的實現效果是一樣的,一個是lambda表示式,一個是函式引用的方式
    Stream<String> lowerCase = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
            .map(s -> s.toLowerCase());

map()函式不僅可以處理資料,還可以轉換資料的型別。如下:

    IntStream lengths = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
            .mapToInt(String::length);

上面程式碼的處理結果是:[6, 4, 7, 5],規則是字串的長度。將管道流的字串,使用mapToInt方法,以String::length為規則進行轉換。當然除了mapToInt,還為我們提供了mapToDouble()和mapToLong()方法。我們可以通過自定義轉換規則函式,返回int、double、long型別的返回值。

期待您的關注

  • 博主最近新寫了一本書:《手摸手教您學習SpringBoot系列-16章97節》
  • 本文轉載註明出處(必須帶連線,不能只轉文字):字母哥部落格。