Collection及其師傅Iterable

        上一節咱們縷清了Collection家族的關係,接下來咱們就來看看這個家族的創始者及其師傅。java

1.  師傅Iterablec++

        Iterable是一個接口類,先看看接口裏面的方法:數組

pic_java_src_iterable

其中第二個和第三個方法,都是java8新增的,看源碼會發現,java8後,能夠在接口裏面定義默認(關鍵字default)的方法(必須實現,能夠空實現),並且實現類中還能夠重寫default方法,這樣一來有點相似抽象類,只不過接口類用來授藝,抽象類用來遺傳。最終給咱們代碼的迭代帶來很大便利。ide

        Iterable裏面最主要的固然迭代器Iterator,Iterator自己是接口,這麼說來接口師傅(水平有限)傳授的都是大道的終極要義,功夫仍是得弟子苦練。後來師傅能力提高(java8來了),能夠給弟子大道的精華(default方法),讓弟子能夠絕不費力直接領悟,甚至弟子還能夠加以創新(重寫),可是要注意多接口實現形成的默認方法衝突問題(衝突很容易解決,就很少說)。關於Iterator在子類的實現能夠查看ArrayList源碼,很簡單,只是你們用得多的是next()方法,不知有沒有注意到previous()方法。值得一提的是在Iterator接口裏面新增了默認方法:forEachRemaining方法,容許傳入一個行爲,其實就相似於Iterable的forEach方法。函數

        一看forEach方法,就知道這是遍歷集合的,可是通常咱們遍歷集合可能有兩種緣由:一篩選出特定的元素(須要返回值);二處理元素(無需返回值)。由此一看這個方法它沒有返回值,頓時就肯定這是處理元素。咱們看看forEach的參數:Consumer。ui

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

        Consumer:FunctionalInterface說明該接口屬於函數式接口。它表示一個接受單個輸入參數而且沒有返回值的操做。不像其餘函數式接口,Consumer接口指望執行帶有反作用的操做,即Consumer的操做可能會更改輸入參數的內部狀態。如今java類的方法裏面能夠直接傳遞函數,而不只限於值了。這在c++裏面叫函數指針。this

        從accept方法可知Consumer能夠表明任意函數,但該函數的參數個數限制爲一個且無返回值。指針

public class Main {

    public static void main(String[] args) {

        //eg.1
        String hello = "hello world!";
        Consumer<String> c = (str) -> System.out.println(str.toUpperCase());
        c.accept(hello);

        //eg.2
        List<Student> list = Arrays.asList(new Student("Ben", 80),
                                           new Student("John", 90));
        Consumer<Student> consumer = new Consumer<Student>() {
            @Override
            public void accept(Student s) {
                s.score *= 0.9;
            }
        };
        //list.forEach(consumer);
        list.forEach(consumer.andThen(consumer));   //每一個元素先執行調用者行爲,而後在執行參數行爲
        list.forEach(new Consumer<Student>() {      //打印
            @Override
            public void accept(Student s) {
                System.out.println(s.name + ": " + s.score);
            }
        });



    }

    static class Student {
        String name;
        int score;

        public Student(String name, int score) {
            this.name = name;
            this.score = score;
        }
    }
}

        至於第三個方法spliterator()返回的是一個分片迭代器,它能夠將集合分紅多個片斷,每一個片斷能夠並行處理,在多核CPU下十分高效。在後面章節我會單獨起一章講解。code

2.  徒弟Collection接口

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



default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
}

default Stream<E> parallelStream() {
    return StreamSupport.stream(spliterator(), true);
}

        在這裏我簡單介紹一下Predicate接口,它也是函數式接口,其實就相似於Consumer,只不過Consumer是處理數據,沒有返回值,而Predicate是進行一些邏輯處理,返回一個boolean值。其餘兩個默認方法是將集合數據流化,便於作一些過濾,也看到了stream()方法裏面也進行了分片迭代處理。

        關於java8新特性Stream的講解,也排在後面的章節。

        好了,兩個接口的講解就到此結束了。

相關文章
相關標籤/搜索