Java Lambda Collection/List篇

Java Lambda Collection/List篇

前言

這篇文章主要接續Lambda基礎篇,主要介紹與自我複習常用的Collection家族中的Lambda方法

Collection

forEach

forEach 是Iterable介面中的default Method原始碼如下

default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

敲黑板 畫重點

  • Collection透過FunctionalInterface "Consumer"讓此介面可以透過lambda實踐。
  • Collection家族都有實作Iterable介面因此都可以使用此forEach方法。

實踐

    private void forExample(List<String> example) {
        example.forEach(System.out::println);
    }

透過ArrayList實踐

  • System.out::println省列了不帶任何參數的method ()->,讓Lambda自動對物件使用此method

removeIf

removeIf是Collection介面本身的方法,原始碼如下

    default boolean removeIf(Predicate<? super E> filter) {
    
        Objects.requireNonNull(filter);
        boolean removed = false;
        final Iterator<E> each = iterator();
        while (each.hasNext()) {
            if (filter.test(each.next())) {
                each.remove();
                removed = true;
            }
        }
        return removed;
    

敲黑板 畫重點

  • 我們看到Predicate<? super E>這個方法,他後面的<? super E>稱為限制符,傳入的物件必須是E這個template的子類別(或是本身)

實踐

    private void removeExample() {
        List<String> example = new ArrayList<>(Arrays.asList("data", "data2", "data"));
        example.removeIf("data2"::equals);
        System.out.println(example.toString());
    }

透過ArrayList實踐

  • 刪除列中的data2字串
    如果是以前的寫法則可能要自己寫一串的for/while去找出此字串,現在lambda讓你輕輕鬆鬆解決

replaceAll

replaceAll method主要定義在List介面,可以對目前的物件做side effect,換句話說可以透過此lambda方法將此collection中的物件做額外的處理,原始碼如下

    default void replaceAll(UnaryOperator<E> operator) {
        Objects.requireNonNull(operator);
        final ListIterator<E> li = this.listIterator();
        while (li.hasNext()) {
            li.set(operator.apply(li.next()));
        }
    }

敲黑板 畫重點

  • replcaceAll方法主要是傳入UnaryOperator介面,依照名稱來解析就是我只對單個物件做操作,而其中的ListIterator則是Iterator介面的擴增,讓這個迭代介面更貼近List的迭代(基本的Iterator是符合每個Collection家族的而此ListIteratpor是專門給List系列的物件),可以看到原始碼使用了ListIteraotr的set方法,這是母介面Iterator沒有提供的。

  • 可以看到在這裡的ListIterator只是單純的介面,他必須依賴目前子類別的this.listIterator方法,因為接下來的範例是以ArrayList進行所以就是依據ArrayList的實作為主,而li.set傳入的operator則是你於外層lambda的邏輯並且傳入迭代的下個物件。

實作

    private void replaceAllExample() {
        List<String> example = new ArrayList<>(Arrays.asList("data", "data", "data"));
        example.replaceAll(x ->
             x = x + "- hi"
        );
        System.out.println(example.toString());
    
  • 簡單的執行邏輯,對每個此ArrayList的字串增加hi字尾。

sort

如同replaceAll定義於List介面,可以對此List的物件做排序。原始碼如下

    default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }

敲黑板 畫重點

  • 此方法主要傳入的參數是Comparator介面,就如同一般使用Comaprator方法撰寫lambda就好(兩個物件間的比對),在方法中可以看到使用Arrays進行sort並將Comparator邏輯傳入,Arrays是Java提供專門對Array系列物件做處理的工具(只要底層是用陣列儲存操作就可以算是Array系列)

  • 而迭代方法如同replaceAll使用List加強版的Iterator

實作

    private void sortExample() {
        List<String> example = new ArrayList<>(Arrays.asList("data1", "data12", "data123"));
        example.sort((str1, str2) -> str2.length() - str1.length());
        System.out.println(example.toString());
    }

結論

其實Collection/List中還有非常非常多的Lambda使用,只是目前我自己最常使用的就是上面列出的。未來如果有更深入的心得會持續補上文章

留言

這個網誌中的熱門文章

Java Lambda Map篇

(InterviewBit) System Design - Design Cache System

設計模式 - 享元模式 (Structural Patterns - Flyweight Design Pattern)