2020你還不會Java8新特性?(學習過程記錄)

Java8(1)新特性介紹及Lambda表達式

這,僅是我學習過程當中記錄的筆記。肯定了一個待研究的主題,對這個主題進行全方面的剖析。筆記是用來方便我回顧與學習的,歡迎你們與我進行交流溝通,共同成長。不止是技術。html

前言:

跟大娃一塊看,把原來的電腦拿出來放中間看視頻用java

--- 之後會有的課程 難度node

  1. 深刻Java 8 難度1
  2. 併發與netty 難度3
  3. JVM 難度4
  4. node 難度2
  5. spring精髓 難度1

課程中提到的知識:

先後端分離的開發,是靠node當作中間的spring

netty,已經成爲國內外互聯網公司的標配。會涉及底層的源代碼的理解。sql

JVM 涉及的東西比較多。雖然每天用,可是沒有深刻理解過。各類鎖,可見性等。與計算機原理息息相關的。express

聖思園主要面對與已經工做的。大部分爲一線的開發人員。 課程必定是完整的。由淺入深的。必定要有一種耐心。 對於基礎很差的,能夠看看之前面授的時候錄製的視頻。不懂的必定要多查資料。編程

在講課過程當中的設計思路:4000塊錢的收費標準。後端

jdk8

介紹:Java 8可謂Java語言歷史上變化最大的一個版本,其承諾要調整Java編程向着函數式風格邁進,這有助於編寫出更爲簡潔、表達力更強,而且在不少狀況下可以利用並行硬件的代碼。本門課程將會深刻介紹Java 8新特性,學員將會經過本門課程的學習深刻掌握Java 8新增特性並能靈活運用在項目中。學習者將學習到如何經過Lambda表達式使用一行代碼編寫Java函數,如何經過這種功能使用新的Stream API進行編程,如何將冗長的集合處理代碼壓縮爲簡單且可讀性更好的流程序。學習建立和消費流的機制,分析其性能,可以判斷什麼時候應該調用API的並行執行特性。api

課程的介紹:數組

  1. Java 8新特性介紹
  2. Lambda表達式介紹
  3. 使用Lambda表達式代替匿名內部類
  4. Lambda表達式的做用
  5. 外部迭代與內部迭代
  6. Java Lambda表達式語法詳解
  7. 函數式接口詳解
  8. 傳遞值與傳遞行爲
  9. Stream深度解析
  10. Stream API詳解
  11. 串行流與並行流
  12. Stream構成
  13. Stream源生成方式
  14. Stream操做類型
  15. Stream轉換
  16. Optional詳解
  17. 默認方法詳解
  18. 方法與構造方法引用
  19. Predicate接口詳解
  20. Function接口詳解
  21. Consumer接口剖析
  22. Filter介紹
  23. Map-Reduce講解、中間操做與終止操做
  24. 新的Date API分析

拉姆達表達式: 函數式編程。之前的叫作命令式的編程。 使用面嚮對象語言就是來操做數據,封裝繼承多態。 函數式編程面向的是行爲。好處:代碼可讀性提升。

開發安卓的時候大量的匿名內部類。

提到的關鍵字: kotlin ,JetBrains 。construction 構造

他之前在學習的時候,翻代碼。

將要講解的各個技術的簡介、

課程講解的時候遇到的工具: Mac , jdk8 ,idea(不少功能是經過插件的形式來實現的)


Java8課程開始

lambda表達式

爲何要使用lambda表示式

  • 在Java中沒法將函數座位參數傳遞給一個方法,也沒法返回一個函數的方法。
  • 在js中,函數的參數是一個函數。返回值是另外一個函數的狀況是很是常見的。是一門經典的函數式語言。

Java匿名內部類。

匿名內部類的介紹

Gradle的使用。能夠徹底使用maven的中央倉庫。 進行安卓的開發時,gradle已經成爲標配了。

lambda: 匿名內部類

my_jButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Button Pressed! ");
            }
        });

改造後

my_jButton.addActionListener(e -> System.out.println("Button Pressed!"));

lambda表達式的基本結構:

(param1,param2,param3) ->{
    
}

函數式編程: 一個接口裏邊只有一個抽象方法。 能夠經過lambda表達式來實例。

關於函數式接口:

  • 若是一個藉口只有一個抽象方法,那麼該接口就是一個函數式接口。
  • 若是咱們在某一個接口上聲明瞭functionalInterface註解,那麼編譯器就會按照函數是藉口的定義來要求改接口。
  • 若是某個接口只有一個抽象方法,可是咱們並無給接口聲明functionnaleInterface註解,編譯器依舊會給改接口看做是函數式接口。

經過實例對函數式接口的理解:

package com.erwa.jdk8;

@FunctionalInterface
interface MyInterface {

    void test();

//    Multiple non-overriding abstract methods found in interface com.erwa.jdk8.MyInterface
//    void te();

    //若是一個接口聲明一個抽象方法,可是這個方法重寫了 object類中的一個方法.
    //接口的抽象方法不會加一.因此依然是函數方法.
    // Object 類是全部類的父類.
    @Override
    String toString();
}

public class Test2 {

    public void myTest(MyInterface myInterface) {
        System.out.println(1);
        myInterface.test();
        System.out.println(2);
    }

    public static void main(String[] args) {
        Test2 test2 = new Test2();
        test2.myTest(() -> {
            System.out.println(3);
        });
    }

}

接口裏邊從1.8開始也能夠有方法實現了。default

默認方法。
   default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
* <p>Note that instances of functional interfaces can be created with
 * lambda expressions, method references, or constructor reference

lambda表達式的做用:

  • lambda表達式爲Java添加了確實的函數式編程特性,使咱們能將函數當作一等公民看待。
  • 在將函數座位一等公民的語言中,lambda表達式的類型是函數。可是在Java中,lambda表達式是對象,他們必須依附於一類特別的對象類型-函數式接口(function interface)

迭代的方式:

  • 外部迭代:
  • 內部迭代:
  • 方法引用:
list.forEach(System.out::println);

接口中能夠有默認方法和靜態方法。

流: stream

/**
     * Returns a sequential {@code Stream} with this collection as its source.
     *
     * <p>This method should be overridden when the {@link #spliterator()}
     * method cannot return a spliterator that is {@code IMMUTABLE},
     * {@code CONCURRENT}, or <em>late-binding</em>. (See {@link #spliterator()}
     * for details.)
     *
     * @implSpec
     * The default implementation creates a sequential {@code Stream} from the
     * collection's {@code Spliterator}.
     *
     * @return a sequential {@code Stream} over the elements in this collection
     * @since 1.8
     */
    default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    }

關於流方式實現的舉例:

public static void main(String[] args) {
        //函數式接口的實現方式
        MyInterface1 i1 = () -> {};
        System.out.println(i1.getClass().getInterfaces()[0]);
        MyInterface2 i2 = () -> {};
        System.out.println(i2.getClass().getInterfaces()[0]);

        // 沒有上下文對象,必定會報錯的.
//        () -> {};

        //經過lambda來實現一個線程.
        new Thread(() -> System.out.println("hello world")).start();

        //有一個list  ,將內容中的首字母變大寫輸出.
        List<String> list = Arrays.asList("hello","world","hello world");
        //經過lambda來實現全部字母編程大寫輸出.
//        list.forEach(item -> System.out.println(item.toUpperCase()));
        //把三個單詞放入到新的集合裏邊.
        List<String> list1 = new ArrayList<>();  //diamond語法. 後邊的<>不用再放類型
//        list.forEach(item -> list1.add(item.toUpperCase()));
//        list1.forEach(System.out::println);

        //進一步的改進. 流的方式
//        list.stream();//單線程
//        list.parallelStream(); //多線程
        list.stream().map(item -> item.toUpperCase()).forEach(System.out::println);//單線程
        list.stream().map(String::toUpperCase).forEach(System.out::println);

        //上邊的兩種方法,都知足函數式接口的方式.
    }

lambda表達式的做

  • 傳遞行爲,而不只僅是值
    • 提高抽象層次
    • API重用性更好
    • 更加靈活

lambda基本語法

  • (argument) -> (body)
  • 如: (arg1,arg2...) -> (body)

Java lambda結構

  • 一個Lambda表達式能夠有0個或者多個參數
  • 參數的類型既能夠明確聲明,也能夠根據上下文來推斷。例如:(int a) 與 (a) 效果相同
  • 全部參數包含在圓括號內,參數之間用逗號相隔。
  • 空圓括號表明參數集爲空。
  • 當只有一個參數,且類型可推倒時。圓括號()可省略。
  • lambda表達式的主體能夠包含0條或多條語句。
  • 若是lambda表達式的主體只有一條語句,花括號{}能夠省略,匿名函數的返回類型與該主體表達式一致。
  • 若是lambda表達式的主體包含一條以上語句,則表達式必須包含在花括號中。匿名函數的韓繪製類型與代碼塊的返回類型一致,諾沒有反回則爲空。

高階函數: 若是一個函數接收一個函數做爲參數,或者返回一個函數做爲返回值,那麼該函數就叫作高階函數.

傳遞行爲的舉例:

public static void main(String[] args) {
        // 函數的測試
        // 傳遞行爲的一種方式.
        FunctionTest functionTest = new FunctionTest();
        int compute = functionTest.compute(1, value -> 2 * value);

        System.out.println(compute);
        System.out.println(functionTest.compute(2,value -> 5+ value));
        System.out.println(functionTest.compute(3,a -> a * a));

        System.out.println(functionTest.convert(5, a -> a + "hello "));

        /**
         * 高階函數:
         * 若是一個函數接收一個函數做爲參數,或者返回一個函數做爲返回值,那麼該函數就叫作高階函數.
         */

    }

    //使用lambda表達式的話,能夠直覺預約義行爲.用的時候傳遞.
    // 即 函數式編程.
    public int compute(int a, Function<Integer, Integer> function) {
        return function.apply(a);
    }

    public String convert(int a, Function<Integer, String> function) {
        return function.apply(a);
    }


    // 以前完成行爲的作法. 提早把行爲定義好,用的時候調用方法. 如:
    public  int method1(int a ){
        return a * 2 ;
    }

Function類中提供的默認方法的講解:

/**
     * Returns a composed function that first applies the {@code before}
     * function to its input, and then applies this function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     返回一個組合的函數。對應用完參數後的結果,再次運行apply
     *
     * @param <V> the type of input to the {@code before} function, and to the
     *           composed function  
     * @param before the function to apply before this function is applied
     * @return a composed function that first applies the {@code before}
     * function and then applies this function
     * @throws NullPointerException if before is null
     *
     * @see #andThen(Function)
     */
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    /**
     * Returns a composed function that first applies this function to
     * its input, and then applies the {@code after} function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of output of the {@code after} function, and of the
     *           composed function
     * @param after the function to apply after this function is applied
     * @return a composed function that first applies this function and then
     * applies the {@code after} function
     * @throws NullPointerException if after is null
     *
     * @see #compose(Function)
     */
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

compose : 組合function, 造成兩個function的串聯。 先執行參數

andThen :先應用當前的函數apply,而後再當作參數再次執行apply。 後執行參數。

identity:輸入什麼返回什麼。

BiFunction: 整合兩個函數的方法。 爲何BiFunction不提供 compose ,只提供andThen呢? 由於若是提供compose方法的話,只能獲取一個參數的返回值。不合理。

public static void main(String[] args) {
        FunctionTest2 functionTest2 = new FunctionTest2();

        // compose
//        System.out.println(functionTest2.compute(2,a -> a * 3,b -> b * b));
        // andThen
//        System.out.println(functionTest2.compute2(2,a -> a * 3,b -> b * b));

        //BiFunction
//        System.out.println(functionTest2.compute3(1,2, (a,b) -> a - b));
//        System.out.println(functionTest2.compute3(1,2, (a,b) -> a * b));
//        System.out.println(functionTest2.compute3(1,2, (a,b) -> a + b));
//        System.out.println(functionTest2.compute3(1,2, (a,b) -> a / b));

        //BiFunction  andThen
        System.out.println(functionTest2.compute4(2,3,(a,b) ->a + b , a -> a * a ));
    }

    //compose : 組合function, 造成兩個function的串聯。  先執行參數
    //andThen :先應用當前的函數apply,而後再當作參數再次執行apply。 後執行參數

    public int compute(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
        return function1.compose(function2).apply(a);
    }

    public int compute2(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
        return function1.andThen(function2).apply(a);
    }

    //BiFunction
    //求兩個參數的和
    //先定義一個抽象的行爲.
    public int compute3(int a, int b, BiFunction<Integer, Integer, Integer> biFunction) {
        return biFunction.apply(a, b);
    }

    //BiFunction  andThen 
    public int compute4(int a, int b, BiFunction<Integer, Integer, Integer> biFunction, Function<Integer, Integer> function) {
        return biFunction.andThen(function).apply(a, b);
    }

測試 函數式接口的實例:

public class PersonTest {
    public static void main(String[] args) {


        List<Person> personList = new ArrayList<>();

        personList.add(new Person("zhangsan", 20));
        personList.add(new Person("zhangsan", 28));
        personList.add(new Person("lisi", 30));
        personList.add(new Person("wangwu", 40));

        PersonTest test = new PersonTest();

        //測試 getPersonUsername
//        List<Person> personList1 = test.getPersonUsername("zhangsan", personList);
//        personList1.forEach(person -> System.out.println(person.getUsername()));


        //測試  getPersonByAge
        List<Person> personByAge = test.getPersonByAge(25, personList);
        personByAge.forEach(person -> System.out.println(person.getAge()));
        
        
        //測試第三種: 自定義輸入行爲
        List<Person> list = test.getPersonByAge2(20,personList,(age,persons) ->{
            return persons.stream().filter(person -> person.getAge() > age).collect(Collectors.toList());
        });
        list.forEach(person -> System.out.println(person.getAge()));

    }


    public List<Person> getPersonUsername(String username, List<Person> personList) {
        return personList.stream().filter(person -> person.getUsername().equals(username)).collect(Collectors.toList());
    }

    public List<Person> getPersonByAge(int age, List<Person> personList) {
        //使用BiFunction的方式
//        BiFunction<Integer, List<Person>, List<Person>> biFunction = (ageOfPerson, list) -> {
//            return  list.stream().filter(person -> person.getAge() > ageOfPerson ).collect(Collectors.toList());
//        };

        //變換以後:
        BiFunction<Integer, List<Person>, List<Person>> biFunction = (ageOfPerson, list) ->
            list.stream().filter(person -> person.getAge() > ageOfPerson ).collect(Collectors.toList());

        return biFunction.apply(age, personList);
    }
    
     //第三種方式, 動做也讓用戶本身定義傳進來
    public List<Person> getPersonByAge2(int age ,List<Person> list,BiFunction<Integer,List<Person>,List<Person>> biFunction){
        return biFunction.apply(age, list);
    }
}

函數式接口的真諦: 傳遞的是行爲,而不是數據

public static void main(String[] args) {
        //給定一個輸入參數,判斷是否知足條件,知足的話返回true
        Predicate<String> predicate = p -> p.length() > 5;
        System.out.println(predicate.test("nnihaoda"));

    }

到如今爲止,只是講解了Java.lang.function包下的幾個最重要的,常用的方法。


2020年01月01日19:03:33 新的一年開始,記錄一下每次學習的時間。

Predicate 謂語。 類中包含的方法:

  • boolean test(T t);
  • default Predicate<T> or(Predicate<? super T> other)
  • default Predicate<T> negate()
  • default Predicate<T> and(Predicate<? super T> other)
  • static <T> Predicate<T> isEqual(Object targetRef)

函數式編程,注重傳遞行爲,而不是傳遞值。

public class PredicateTest2 {
    /**
     * 測試Predicate中的test方法
     */
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);

        PredicateTest2 predicateTest2 = new PredicateTest2();
        //獲取大於5的數字
        predicateTest2.getAllFunction(list,item -> item > 5);
        System.out.println("--------");
        //獲取全部的偶數
        predicateTest2.getAllFunction(list,item -> item % 2 ==0);
        System.out.println("--------");
        //獲取全部的數字
        predicateTest2.getAllFunction(list,item -> true);
        //獲取大於5而且是偶數的
        System.out.println("--------");
        predicateTest2.testAnd(list,item -> item > 5,item -> item % 2 == 0);
    }

    public void getAllFunction(List<Integer> list, Predicate<Integer> predicate){
        for (Integer integer : list) {
            if (predicate.test(integer)) {
                System.out.println(integer);
            }
        }
    }
  
     // test or  and
    public  void testAnd(List<Integer> list,Predicate<Integer> 		  integerPredicate,Predicate<Integer> integerPredicate1){
        for (Integer integer : list) {
            if (integerPredicate.and(integerPredicate1).test(integer)) {
                System.out.println(integer);
            }  
        }
    }
}

lambda表達式到底給咱們帶來了什麼?原來經過面向對象的時候一個方法只能執行一種功能。如今傳遞的是行爲,一個方法能夠屢次調用。

邏輯與或非三種的理解.


Supplier類 供應廠商;供應者 (不接收參數,返回結果)

用於什麼場合? 工廠


2020年1月3日08:06:28
BinaryOperator 接口

public class SinaryOpertorTest {

    public static void main(String[] args) {

        SinaryOpertorTest sinaryOpertorTest = new SinaryOpertorTest();

        System.out.println(sinaryOpertorTest.compute(1,2,(a,b) -> a+b));

        System.out.println("-- -- - - - -- -");

        System.out.println(sinaryOpertorTest.getMax("hello123","world",(a,b) -> a.length() - b.length()));
    }

    private int compute(int a, int b, BinaryOperator<Integer> binaryOperator) {
        return binaryOperator.apply(a, b);
    }

    private String getMax(String a, String b, Comparator<String> comparator) {
        return BinaryOperator.maxBy(comparator).apply(a, b);
    }
}

Optional final :Optional 不要試圖用來當作參數, 通常只用來接收返回值,來規避值的空指針異常的問題。

  • empty()
  • of()
  • ofNullable()
  • isPresent()
  • get()
  • ...
public class OptionalTest {

    public static void main(String[] args) {
        Optional<String> optional = Optional.of("hello");

        //不肯定是否爲 空是 調用和這個方法
//        Optional<String> optional2 = Optional.ofNullable("hello");

//        Optional<String> optional1 = Optional.empty();


        //過期
//        if (optional.isPresent()) {
//            System.out.println(optional.get());
//        }

        optional.ifPresent(item -> System.out.println(item));
        System.out.println(optional.orElse("nihao"));
        System.out.println(optional.orElseGet(() -> "nihao"));

    }
public class OptionalTest2 {
    public static void main(String[] args) {
        Employee employee = new Employee();
        employee.setName("dawa");

        Employee employee1 = new Employee();
        employee1.setName("erwa");

        List<Employee> list = Arrays.asList(employee, employee1);
        Company company = new Company("gongsi", list);

        Optional<Company> optionalCompany = Optional.ofNullable(company);

        System.out.println(optionalCompany.map(company1 -> company1.getList()).orElse(Collections.emptyList()));
    }
}

Java8(2)方法引用詳解及Stream流介紹

2020你還不會Java8新特性?方法引用詳解及Stream 流介紹和操做方式詳解(三)

方法引用詳解

方法引用: method reference

方法引用其實是Lambda表達式的一種語法糖

咱們能夠將方法引用看做是一個「函數指針」,function pointer

方法引用共分爲4類:

  1. 類名::靜態方法名
  2. 引用名(對象名)::實例方法名
  3. 類名::實例方法名 (比較很差理解,個地方調用的方法只有一個參數,爲何還能正常調用呢? 由於調用比較時,第一個對象來調用getStudentByScore1. 第二個對象來當作參數)
  4. 構造方法引用: 類名::new
public class StudentTest {

    public static void main(String[] args) {
        Student student = new Student("zhangsan",10);
        Student student1 = new Student("lisi",40);
        Student student2 = new Student("wangwu",30);
        Student student3 = new Student("zhaoliu",550);

        List<Student> list = Arrays.asList(student, student2, student3, student1);

//        list.forEach(item -> System.out.println(item.getName()));

        //1. 類名 :: 靜態方法
//        list.sort((studentpar1,studentpar2) -> Student.getStudentByScore(studentpar1,studentpar2));
        list.sort(Student::getStudentByScore);
        list.forEach(item -> System.out.println(item.getScore()));
        System.out.println(" - - - - - - - -- ");

        // 2. 引用名(對象名)::實例方法名
        StudentMethod studentMethod = new StudentMethod();
        list.sort(studentMethod::getStudentBySource);
        list.forEach(item -> System.out.println(item.getScore()));
        System.out.println(" - - - -- -- ");

        // 3. 類名:: 實例方法名
        // 這個地方調用的方法只有一個參數,爲何還能正常調用呢? 由於調用比較時,第一個對象來調用getStudentByScore1. 第二個對象來當作參數
        list.sort(Student::getStudentByScore1);
        list.forEach(item -> System.out.println(item.getScore()));
        System.out.println("- - - - - - - -");

        // 原生的sort 來舉個例子
        List<String> list1 = Arrays.asList("da", "era", "a");
//        Collections.sort(list1,(city1,city2) -> city1.compareToIgnoreCase(city2));
        list1.sort(String::compareToIgnoreCase);
        list1.forEach(System.out::println);
        System.out.println("- - - - - - -- ");

        //4. 構造方法引用
        StudentTest studentTest = new StudentTest();
        System.out.println(studentTest.getString(String::new));
    }

    public String getString(Supplier<String> supplier) {
        return supplier.get()+"hello";
    }

}

默認方法

defaute method

默認方法是指實現此接口時,默認方法已經被默認實現。

引入默認方法最重要的做用就是Java要保證向後兼容。

情景一: 一個類,實現了兩個接口。兩個接口中有一個相同名字的默認方法。此時會報錯,須要從寫這個重名的方法

情景二: 約定:實現類的優先級比接口的優先級要高。 一個類,實現一個接口,繼承一個實現類。接口和實現類中有一個同名的方法,此時,此類會使用實現類中的方法。


Stream 流介紹和操做方式詳解

Collection提供了新的stream()方法。

流不存儲值,經過管道的方式獲取值。

本質是函數式的,對流的操做會生成一個結果,不過並不會修改底層的數據源,集合能夠做爲流的底層數據源。

延遲查找,不少流操做(過濾、映射、排序等)等能夠延遲實現。

經過流的方式能夠更好的操做集合。使用函數式編程更爲流程。與lambda表達式搭配使用。

流由3部分構成:

  1. 零個或多箇中間操做(操做的是誰?操做的是源)
  2. 終止操做(獲得一個結果)

流操做的分類:

  1. 惰性求值(中間操做)
  2. 及早求值(種植操做)

使用鏈式的調用方式sunc as : stream.xxx().yyy().zzz().count(); 沒有count的時候前邊的三個方法不會被調用。後續會進行舉例。

掌握流經常使用的api,瞭解底層。

流支持並行化,能夠多線程操做。迭代器不支持並行化。

流怎麼用?

流的建立方式

  1. 經過靜態方法 : Stream stream = Stream.of();
  2. 經過數組:Arrays.stream();
  3. 經過集合建立對象:Stream stream = list.stream;

流的簡單應用

public static void main(String[] args) {
        IntStream.of(1,2,4,5,6).forEach(System.out::println);
        IntStream.range(3, 8).forEach(System.out::println);
        IntStream.rangeClosed(3, 8).forEach(System.out::println);
    }

舉例:將一個數組中的數字都乘以二,而後求和。

public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        System.out.println(list.stream().map(i -> i*2).reduce(0,Integer::sum));
    }

函數式編程和傳統面向對象編程根本上有什麼不一樣?

傳統面向對象編程傳遞的是數據。函數式編程經過方法傳遞的是一種行爲,行爲指導了函數的處理,根據行爲對數據進行加工。

舉例:流轉換成list的練習

public static void main(String[] args) {

        Stream<String> stream = Stream.of("hello", "world", "hello world");
//        String[] stringArray = stream.toArray(length -> new String[length]);
        //替換成方法引用的方式  --> 構造方法引用.
        String[] stringArray = stream.toArray(String[]::new);
        Arrays.asList(stringArray).forEach(System.out::println);
        System.out.println("- - - - - - - - - - -");

        //將流轉換成list,   有現成的封裝好的方法
        Stream<String> stream1 = Stream.of("hello", "world", "hello world");
        List<String> collect = stream1.collect(Collectors.toList());// 自己是一個終止操做
        collect.forEach(System.out::println);

        System.out.println("- - - - - - ");

        //使用原生的 collect 來將流轉成List
        Stream<String> stream2 = Stream.of("hello", "world", "hello world");
//        List<String> lis = stream2.collect(() -> new ArrayList(), (theList, item) -> theList.add(item),
//                (theList1, theList2) -> theList1.addAll(theList2));
        // 將上面的轉換成方法引用的方式  -- 這種方法很差理解.
        List<String> list = stream2.collect(LinkedList::new, LinkedList::add, LinkedList::addAll);
        //這種方法,若是想要返回ArrayList也能夠實現.
//        List<String> list1 = stream2.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
        list.forEach(System.out::println);
    }

Collectors類中包含了流轉換的多個輔助類

舉例: 將流 轉成各類類型的數據。

public static void main(String[] args) {
        Stream<String> stream = Stream.of("hello", "world", "hello world");

        //將流轉換成List 另外一種方法
//        List<String> list= stream.collect(Collectors.toCollection(ArrayList::new));
//        list.forEach(System.out::println);

        //將流轉成set
//        Set<String> set = stream.collect(Collectors.toSet());
        //轉成TreeSet
//        TreeSet<String> set = stream.collect(Collectors.toCollection(TreeSet::new));
//        set.forEach(System.out::println);

        //轉成字符串
        String string = stream.collect(Collectors.joining());
        System.out.println(string);

        //Collectors 類中有多重輔助的方法.

    }

**遇到問題的時候,先思考一下可否用方法引用的方式,使用流的方式來操做。**由於用起來比較簡單。

舉例:將集合中的每個元素 轉換成大寫的字母, 給輸出來。

public static void main(String[] args) {
        //將集合中的每個元素 轉換成大寫的字母, 給輸出來
        List<String> list = Arrays.asList("hello","world","hello world");

        //轉成字符串,而後轉成大寫.
//        System.out.println(list.stream().collect(Collectors.joining()).toUpperCase());
        //上面的代碼 能夠轉換成下邊的代碼.
//        System.out.println(String.join("", list).toUpperCase());

        //視頻上給出的   仍是List的大寫
        list.stream().map(String::toUpperCase).collect(Collectors.toList()).forEach(System.out::println);
  
  //將集合 的數據給平方一下輸出.
        List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5);
        list1.stream().map(item -> item * item).collect(Collectors.toList()).forEach(System.out::println);

}

流中的 .map () 方法,是對集合中的每個數據進行一下操做。

stream 的 flat操做。 打平操做。

public static void main(String[] args) {
// 舉例:   flag 的操做, 打平. 一個集合中有三個數組, 打平以後,三個數組的元素依次排列.
Stream<List<Integer>> stream = Stream.of(Arrays.asList(1), Arrays.asList(2, 3), Arrays.asList(4, 5));
//將裏邊每個ArrayList的數據 作一個平方.  而後打平. 輸出一個list
stream.flatMap(theList -> theList.stream()).map(item -> item * item).forEach(System.out::println);
}

Stream 其餘方法介紹:

public static void main(String[] args) {
//        stream 其餘方法介紹.

        //  generate(). 生成stream對象
        Stream<String> stream = Stream.generate(UUID.randomUUID()::toString);
//        System.out.println(stream.findFirst().get());
// findFirst,找到第一個對象.而後就短路了,會返回一個Optional對象(爲了不NPE),不符合函數式編程
//        stream.findFirst().isPresent(System.out::print);

        // iterate()     會生成 一個 無限的串行流.
        // 通常不會單獨使用. 會使用limit  來限制一下總長度.
        Stream.iterate(1, item -> item + 2).limit(6).forEach(System.out::println);
    }

Stream 運算練習:(Stream提供了各類操做符)

舉例:找出該流中大於2的元素,而後每一個元素*2 ,而後忽略掉流中的前兩個元素,而後再取流中的前兩個元素,最後求出流元素中的總和.

Stream<Integer> stream = Stream.iterate(1, item -> item + 2).limit(6);
        //找出該流中大於2的元素,先使用filter()過濾.
        //每一個元素*2 使用mapToInt 避免重複拆箱.
        //忽略掉流中的前兩個元素; 使用 skip(2)
        //再取流中的前兩個元素;  使用limit(2)
        //求出流元素中的總和.  使用sum()
System.out.println(stream.filter(item -> item>2).mapToInt(item -> item * 2).skip(2).limit(2).sum());

舉例:找出該流中大於2的元素,而後每一個元素*2 ,而後忽略掉流中的前兩個元素,而後再取流中的前兩個元素,最後找到最小的元素.

// .min() 返回的是IntOptional.
//        System.out.println(stream.filter(item -> item>2).mapToInt(item -> item * 2).skip(2).limit(2).min());
        //應該這樣調用. 上邊的可能會出NPE異常
        stream.filter(item -> item>2).mapToInt(item -> item * 2).skip(2).limit(2).min().ifPresent(System.out::println);

舉例:獲取最大值,最小值,求和等各類操做。 .summaryStatistics();

image-20200104172236805

在練習的過程當中發現了一個問題。若是是這樣連續打印兩條對流操做以後的結果。會報流未關閉的異常。

image-20200104170801230

image-20200104172608140

注意事項:流被重複使用了,或者流被關閉了,就會出異常。

如何避免:使用方法鏈的方式來處理流。 具體出現的緣由,後續進行詳細的源碼講解。


舉例 :中間操做(惰性求值) 和停止操做(及早求值)本質的區別

public static void main(String[] args) {
    List<String> list = Arrays.asList("hello", "world", "hello world");

    //首字母轉大寫
    list.stream().map(item ->{
        String s = item.substring(0, 1).toUpperCase() + item.substring(1);
        System.out.println("test");
        return s;
    }).forEach(System.out::println);
    //沒有遇到停止操做時,是不會執行中間操做的.是延遲的
    // 遇到.forEach() 停止操做時,纔會執行中間操做的代碼
}

舉例:流使用順序不一樣的區別

//程序不會中止
IntStream.iterate(0,i->(i+1)%2).distinct().limit(6).forEach(System.out::println);
//程序會中止
IntStream.iterate(0,i->(i+1)%2).limit(6).distinct().forEach(System.out::println);

Stream底層深刻

  • 和迭代器不一樣的是,Stream能夠並行化操做,迭代器只能命令式地、串行化操做

  • 當使用穿行方式去遍歷時,每一個item讀完後再讀下一個item

  • 使用並行去遍歷時,數據會被分紅多個段,其中每個都在不一樣的線程中處理,而後將結果一塊兒輸出。

  • Stream的並行操做依賴於Java7中引入的Fork/Join框架。

流(Stream)由3部分構成:

  1. 源(Source)
  2. 零個或多箇中間操做(Transforming values)(操做的是誰?操做的是源)
  3. 終止操做(Operations)(獲得一個結果)

內部迭代和外部迭代

描述性的語言:sql和Stream的對比

select name from student where age > 20 and address = 'beijing' order by desc;

===================================================================================

Student.stream().filter(student -> student.getAge >20 ).filter(student -> student.getAddress().equals("beijing")).sorted(..).forEach(student -> System.out.println(student.getName));

上述的描述,並無明確的告訴底層具體要怎麼作,只是發出了描述性的信息。這種流的方式就叫作內部迭代。針對於性能來講,流的操做確定不會下降性能。

外邊迭代舉例: jdk8之前的用的方式。

List<Student> list = new ArrayList<>();

for(int i = 0 ;i <= students.size();i++){

​ Student student = students.get(i);

If(student.getAge() > 20 )

​ list.add(student);

}

Collections.sort(list.....)

list.forEach().....

Stream的出現和集合是密不可分的。

集合關注的是數據與數據存儲自己,流關注的則是對數據的計算。

流與迭代器相似的一點是:流是沒法重複使用或消費的。

如何區分中間操做和停止操做:

中間操做都會返回一個Stream對象,好比說返回Stream<Student>,Stream<Integer>,Stream<String>;

停止操做則不會返回Stream類型,可能不返回值,也可能返回其餘類型的單個值。


並行流的基本使用

舉例: 串行流和並行流的簡單舉例比較

public static void main(String[] args) {
    // 串行流和並行流的比較
    List<String> list = new ArrayList<>(5000000);

    for (int i = 0; i < 5000000; i++) {
        list.add(UUID.randomUUID().toString());
    }

    System.out.println("開始排序");
    long startTime = System.nanoTime();
    //   list.parallelStream().sorted().count(); //串行流
    list.parallelStream().sorted().count(); //並行流
    long endTime = System.nanoTime();
    long millis = TimeUnit.NANOSECONDS.toMillis(endTime - startTime);
    System.out.println("排序時間爲: "+ millis);
}

image-20200104183834756

image-20200104183924340

結果如圖,並行流和串行流時間上錯了4倍。

舉例: 打印出列表中出來第一個長度爲5的單詞.. 同時將長度5打印出來.

public static void main(String[] args) {
        List<String> list = Arrays.asList("hello", "world", "hello world");

//        list.stream().mapToInt(item -> item.length()).filter(length -> length ==5)
//                      .findFirst().ifPresent(System.out::println);

        list.stream().mapToInt(item -> {
            int length = item.length();
            System.out.println(item);
            return length;
        }).filter(length -> length == 5).findFirst().ifPresent(System.out::println);
    //返回的是hello  , 不包含 world.  
    }

返回的是hello , 不包含 world.

流的操做原理: 把流想成一個容器,裏邊存儲的是對每個元素的操做。操做時,把操做串行化。對同一個元素進行串行的操做。操做中還包含着短路操做。

舉例: 找出 這個集合中全部的單詞,並且要去重. flatMap()的使用。

public static void main(String[] args) {
        //舉例; 找出 這個集合中全部的單詞,並且要去重.
        List<String> list = Arrays.asList("hello welcome", "world hello", "hello world", "hello hello world");

//        list.stream().map(item -> item.split(" ")).distinct()
//                .collect(Collectors.toList()).forEach(System.out::println);

        //使用map不能知足需求, 使用flatMap
        list.stream().map(item -> item.split(" ")).flatMap(Arrays::stream)
                .distinct().collect(Collectors.toList()).forEach(System.out::println);

        //結果爲  hello  welcome world 
    }

舉例:組合起來. 打印出 hi zhangsan , hi lisi , hi wangwu , hello zhangsan , hello lisi .... flatMap()的使用。

public static void main(String[] args) {

    //組合起來. 打印出  hi zhangsan , hi lisi , hi wangwu , hello zhangsan , hello lisi ....
    List<String> list = Arrays.asList("Hi", "Hello", "你好");
    List<String> list1 = Arrays.asList("zhangsan", "lisi", "wangwu");

    List<String> collect = list.stream().flatMap(item -> list1.stream().map(item2 -> item + " " +
            item2)).collect(Collectors.toList());

    collect.forEach(System.out::println);

}

舉例: 流對分組/分區操做的支持. group by / protition by

public static void main(String[] args) {
        //數據準備.
        Student student1 = new Student("zhangsan", 100, 20);
        Student student2 = new Student("lisi", 90, 20);
        Student student3 = new Student("wangwu", 90, 30);
        Student student4 = new Student("zhangsan", 80, 40);
        List<Student> students = Arrays.asList(student1, student2, student3, student4);

        //對學生按照姓名分組.
        Map<String, List<Student>> listMap = students.stream().collect(Collectors.groupingBy(Student::getName));
        System.out.println(listMap);

        //對學生按照分數分組.
        Map<Integer, List<Student>> collect = students.stream().collect(Collectors.groupingBy(Student::getScore));
        System.out.println(collect);

        //按照年齡分組.
        Map<Integer, List<Student>> ageMap = students.stream().collect(Collectors.groupingBy(Student::getAge));
        System.out.println(ageMap);

        //按照名字分組後,獲取到每一個分組的元素的個數.
        Map<String, Long> nameCount = students.stream().collect(Collectors.groupingBy(Student::getName, Collectors.counting()));
        System.out.println(nameCount);

        //按照名字分組,求得每一個組的平均值.
        Map<String, Double> doubleMap = students.stream().collect(Collectors.groupingBy(Student::getName, Collectors.averagingDouble(Student::getScore)));
        System.out.println(doubleMap);
   
   			//分區,  分組的一種特例. 只能分兩個組 true or flase .   partitioning  By
        Map<Boolean, List<Student>> collect1 = students.stream().collect(Collectors.partitioningBy(student -> student.getScore() >= 90));
        System.out.println(collect1);

    }

Java8(3)Collector類源碼分析

繼續學習Java8 新特性。

Collector類源碼分析2020了你還不會Java8新特性?

jdk8是怎麼對底層完成支持的。不瞭解底層,平時用還能夠,可是遇到問題的時候就會卡在那裏。遲遲滅有解決方案。在學習一門新技術時,先學習怎麼去用,不要執着於源碼。可是隨着用的愈來愈多,你去了解底層是比較好的一種學習方法。

有多種方法能夠實現同一個功能.什麼方式更好呢? 越具體的方法越好.   減小自動裝箱拆箱操做
  1. collect : 收集器
  2. Collector做爲collect方法的參數。
  3. Collector做爲一個接口。它是一個可變的匯聚操做,將輸入元素累計到一個可變的結果容器中;它會在全部元素都處理完畢後將累計的結果做爲一個最終的表示(這是一個可選操做);它支持串行與並行兩種方式執行。(並非說並行必定比串行快。)
  4. Collects自己提供了關於Collectoe的常見匯聚實現,Collectors自己其實是一個工廠。
  5. 爲了確保串行和並行的結果一致,須要進行額外的處理。必需要知足兩個約束。 identity 同一性 associativity 結合性
  6. 同一性:對於任何一條並行線路來講 ,須要知足a == combiner.apply(a, supplier.get())。舉例來講: (List<String> list1,List<String> list2 -> {list1.addAll(list2);return list1}) 結合性: 下方有舉例。

Collector收集器的實現源碼詳解

/**
 * A <a href="package-summary.html#Reduction">mutable reduction operation</a> that
 * accumulates input elements into a mutable result container, optionally transforming
 * the accumulated result into a final representation after all input elements
 * have been processed.  Reduction operations can be performed either sequentially
 * or in parallel.
 
 	Collector做爲一個接口。它是一個可變的匯聚操做,將輸入元素累計到一個可變的結果容器中;它會在全部元素都處理	完畢後將累計的結果做爲一個最終的表示(這是一個可選操做);它支持串行與並行兩種方式執行。(並非說並行必定比串行快。)
  
 * <p>Examples of mutable reduction operations include:
 * accumulating elements into a {@code Collection}; concatenating
 * strings using a {@code StringBuilder}; computing summary information about
 * elements such as sum, min, max, or average; computing "pivot table" summaries
 * such as "maximum valued transaction by seller", etc.  The class {@link Collectors}
 * provides implementations of many common mutable reductions.
 
 Collects自己提供了關於Collectoe的常見匯聚實現,Collectors自己其實是一個工廠。
 
 * <p>A {@code Collector} is specified by four functions that work together to
 * accumulate entries into a mutable result container, and optionally perform
 * a final transform on the result.  They are: <ul>
 *     <li>creation of a new result container ({@link #supplier()})</li>
 *     <li>incorporating a new data element into a result container ({@link #accumulator()})</li>
 *     <li>combining two result containers into one ({@link #combiner()})</li>
 *     <li>performing an optional final transform on the container ({@link #finisher()})</li>
 * </ul>
 
 	Collector 包含了4個參數
 
 * <p>Collectors also have a set of characteristics, such as
 * {@link Characteristics#CONCURRENT}, that provide hints that can be used by a
 * reduction implementation to provide better performance.
 *
 * <p>A sequential implementation of a reduction using a collector would
 * create a single result container using the supplier function, and invoke the
 * accumulator function once for each input element.  A parallel implementation
 * would partition the input, create a result container for each partition,
 * accumulate the contents of each partition into a subresult for that partition,
 * and then use the combiner function to merge the subresults into a combined
 * result.
 
   舉例說明: 
  1,2, 3, 4 	四個部分結果。
  1,2 -》 5	
  5,3 -》 6
  6,4 -》 6  
 
 
 ### 同一性和結合性的解析: 
 
 * <p>To ensure that sequential and parallel executions produce equivalent
 * results, the collector functions must satisfy an <em>identity</em> and an
 * <a href="package-summary.html#Associativity">associativity</a> constraints.
 
 爲了確保串行和並行的結果一致,須要進行額外的處理。必需要知足兩個約束。
             identity 同一性
 				associativity  結合性
 
 * <p>The identity constraint says that for any partially accumulated result,
 * combining it with an empty result container must produce an equivalent
 * result.  That is, for a partially accumulated result {@code a} that is the
 * result of any series of accumulator and combiner invocations, {@code a} must
 * be equivalent to {@code combiner.apply(a, supplier.get())}.
  
	同一性: 對於任何一條並行線路來講,須要知足a == combiner.apply(a, supplier.get())
 
 * <p>The associativity constraint says that splitting the computation must
 * produce an equivalent result.  That is, for any input elements {@code t1}
 * and {@code t2}, the results {@code r1} and {@code r2} in the computation
 * below must be equivalent:
 * <pre>{@code
 *     A a1 = supplier.get();				串行: 
 *     accumulator.accept(a1, t1);  第一個參數,每次累加的中間結果。 第二個參數,下一個要處理的參數
 *     accumulator.accept(a1, t2);
 *     R r1 = finisher.apply(a1);  // result without splitting
 *		
 *     A a2 = supplier.get();				並行: 
 *     accumulator.accept(a2, t1);  第一個參數,每次累加的中間結果。 第二個參數,下一個要處理的參數
 *     A a3 = supplier.get();
 *     accumulator.accept(a3, t2);
 *     R r2 = finisher.apply(combiner.apply(a2, a3));  // result with splitting
 * } </pre>
 
 結合性: 如上例。  最終要求 r1 == r2 
 
 * <p>For collectors that do not have the {@code UNORDERED} characteristic,
 * two accumulated results {@code a1} and {@code a2} are equivalent if
 * {@code finisher.apply(a1).equals(finisher.apply(a2))}.  For unordered
 * collectors, equivalence is relaxed to allow for non-equality related to
 * differences in order.  (For example, an unordered collector that accumulated
 * elements to a {@code List} would consider two lists equivalent if they
 * contained the same elements, ignoring order.)

 對於無序的收集器來講,等價性就被放鬆了,會考慮到順序上的區別對應的不相等性。
 兩個集合中包含了相同的元素,可是忽略了順序。這種狀況下兩個的集合也是等價的。
 
 
 ### collector複合與注意事項:
 
 * <p>Libraries that implement reduction (匯聚) based on {@code Collector}, such as
 * {@link Stream#collect(Collector)}, must adhere to the following constraints:
 * <ul>  
 *     <li>The first argument passed to the accumulator function, both
 *     arguments passed to the combiner function, and the argument passed to the
 *     finisher function must be the result of a previous invocation of the
 *     result supplier, accumulator, or combiner functions.</li>
 				
 *     <li>The implementation should not do anything with the result of any of
 *     the result supplier, accumulator, or combiner functions other than to
 *     pass them again to the accumulator, combiner, or finisher functions,
 *     or return them to the caller of the reduction operation.</li>
 
			 具體的實現來講,不該該對中間返回的結果進行額外的操做。除了最終的返回的結果。
 		
 *     <li>If a result is passed to the combiner or finisher
 *     function, and the same object is not returned from that function, it is
 *     never used again.</li>
 
 			若是一個結果被傳遞給combiner or finisher,可是並無返回一個你傳遞的對象,說明你生成了一個新的結果或者建立了新的對象。這個結果就不會再被使用了。
 			
 *     <li>Once a result is passed to the combiner or finisher function, it
 *     is never passed to the accumulator function again.</li>
 
 				一旦一個結果被傳遞給了 combiner or finisher 函數,他就不會再被傳遞給了accumulator函數了。
 
 *     <li>For non-concurrent collectors, any result returned from the result
 *     supplier, accumulator, or combiner functions must be serially
 *     thread-confined.  This enables collection to occur in parallel without
 *     the {@code Collector} needing to implement any additional synchronization.
 *     The reduction implementation must manage that the input is properly
 *     partitioned, that partitions are processed in isolation, and combining
 *     happens only after accumulation is complete.</li>
 
 			線程和線程之間的處理都是獨立的,最終結束時再進行合併。
 			
 *     <li>For concurrent collectors, an implementation is free to (but not
 *     required to) implement reduction concurrently.  A concurrent reduction
 *     is one where the accumulator function is called concurrently from
 *     multiple threads, using the same concurrently-modifiable result container,
 *     rather than keeping the result isolated during accumulation.
 *     A concurrent reduction should only be applied if the collector has the
 *     {@link Characteristics#UNORDERED} characteristics or if the
 *     originating data is unordered.</li>
 	
 			若是不是併發收集器,4個線程會生成4箇中間結果。
 			是併發收集器的話,4個線程會同時調用一個結果容器。
 
 * </ul>
 *
 * <p>In addition to the predefined implementations in {@link Collectors}, the
 * static factory methods {@link #of(Supplier, BiConsumer, BinaryOperator, Characteristics...)}
 * can be used to construct collectors.  For example, you could create a collector
 * that accumulates widgets into a {@code TreeSet} with:
 *
 * <pre>{@code
 *     Collector<Widget, ?, TreeSet<Widget>> intoSet =
 *         Collector.of(TreeSet::new, TreeSet::add,
 *                      (left, right) -> { left.addAll(right); return left; });
 * }</pre>
 
 經過Collector.of(傳進一個新的要操做的元素,結果容器處理的步驟,多線程處理的操做)
 將流中的每一個Widget 添加到TreeSet中
 
 
 * (This behavior is also implemented by the predefined collector
 * {@link Collectors#toCollection(Supplier)}).
 *
 * @apiNote  
 * Performing a reduction operation with a {@code Collector} should produce a
 * result equivalent to:
 * <pre>{@code
 *     R container = collector.supplier().get();
 *     for (T t : data)
 *         collector.accumulator().accept(container, t);
 *     return collector.finisher().apply(container);
 * }</pre>
 
 	api的說明:  collector的finisher匯聚的實現過程。
 
 * <p>However, the library is free to partition the input, perform the reduction
 * on the partitions, and then use the combiner function to combine the partial
 * results to achieve a parallel reduction.  (Depending on the specific reduction
 * operation, this may perform better or worse, depending on the relative cost
 * of the accumulator and combiner functions.)
 
 性能取決於accumulator and combiner的代價。  也就是說 並行流 並不必定比串行流效率高。
 
 * <p>Collectors are designed to be <em>composed</em>; many of the methods
 * in {@link Collectors} are functions that take a collector and produce
 * a new collector.  For example, given the following collector that computes
 * the sum of the salaries of a stream of employees:
 * <pre>{@code
 *     Collector<Employee, ?, Integer> summingSalaries
 *         = Collectors.summingInt(Employee::getSalary))
 * }</pre>
 
  蒐集器是能夠組合的:  take a collector and produce a new collector.  
  蒐集器的實現過程。  如  員工的工資的求和。
 
 * If we wanted to create a collector to tabulate the sum of salaries by
 * department, we could reuse the "sum of salaries" logic using
 * {@link Collectors#groupingBy(Function, Collector)}:
 * <pre>{@code
 *     Collector<Employee, ?, Map<Department, Integer>> summingSalariesByDept
 *         = Collectors.groupingBy(Employee::getDepartment, summingSalaries);
 * }</pre>
 
 若是咱們想要新建一個蒐集器,咱們能夠複用以前的蒐集器。
 實現過程。
 
 * @see Stream#collect(Collector)
 * @see Collectors
 *
 * @param <T> the type of input elements to the reduction operation
 			<T>  表明 流中的每個元素的類型。
 * @param <A> the mutable accumulation type of the reduction operation (often
 *            hidden as an implementation detail)
 			<A>  表明 reduction操做的可變容器的類型。表示中間操做生成的結果的類型(如ArrayList)。
 * @param <R> the result type of the reduction operation
 			<R>  表明	結果類型
 * @since 1.8
 */
public interface Collector<T, A, R>{
   /**
     * A function that creates and returns a new mutable result container.
     *	A就表明每一次返回結果的類型
     * @return a function which returns a new, mutable result container
     */
    Supplier<A> supplier();   // 提供一個結果容器
	
    /**
     * A function that folds a value into a mutable result container.
     *	A表明中間操做返回結果的類型。 T是下一個代操做的元素的類型。
     * @return a function which folds a value into a mutable result container
     */
    BiConsumer<A, T> accumulator();    //不斷的向結果容器中添加元素。

    /**
     * A function that accepts two partial results and merges them.  The
     * combiner function may fold state from one argument into the other and
     * return that, or may return a new result container.
     *  A 中間操做返回結果的類型。
     * @return a function which combines two partial results into a combined
     * result
     */
    BinaryOperator<A> combiner();   //在多線程中  合併 部分結果。 
  /**
  和並行流緊密相關的
	接收兩個結果,將兩個部分結果合併到一塊兒。
  combiner函數,有4個線程同時去執行,那麼就會有生成4個部分結果。
  
  舉例說明: 
  1,2, 3, 4 	四個部分結果。
  1,2 -》 5	
  5,3 -》 6
  6,4 -》 6  
   1,2合併返回5  屬於return a new result container. 
   6,4合併返回6,屬於The combiner function may fold state from one argument into the other and  return that。
   */

    /**
     * Perform the final transformation from the intermediate accumulation type
     * {@code A} to the final result type {@code R}.
     *R 是最終返回結果的類型。
     * <p>If the characteristic {@code IDENTITY_TRANSFORM} is
     * set, this function may be presumed to be an identity transform with an
     * unchecked cast from {@code A} to {@code R}.
     * 
     * @return a function which transforms the intermediate result to the final
     * result
     */
    Function<A, R> finisher();  //  合併中間的值,給出返回值。
  
    /**
     * Returns a {@code Set} of {@code Collector.Characteristics} indicating
     * the characteristics of this Collector.  This set should be immutable.
     *
     * @return an immutable set of collector characteristics
     */
    Set<Characteristics> characteristics();   //特徵的集合

    /**
     * Returns a new {@code Collector} described by the given {@code supplier},
     * {@code accumulator}, and {@code combiner} functions.  The resulting
     * {@code Collector} has the {@code Collector.Characteristics.IDENTITY_FINISH}
     * characteristic.
     *
     * @param supplier The supplier function for the new collector
     * @param accumulator The accumulator function for the new collector
     * @param combiner The combiner function for the new collector
     * @param characteristics The collector characteristics for the new
     *                        collector
     * @param <T> The type of input elements for the new collector
     * @param <R> The type of intermediate accumulation result, and final result,
     *           for the new collector
     * @throws NullPointerException if any argument is null
     * @return the new {@code Collector}
     */
    public static<T, R> Collector<T, R, R> of(Supplier<R> supplier,
                                              BiConsumer<R, T> accumulator,
                                              BinaryOperator<R> combiner,
                                              Characteristics... characteristics) {
        Objects.requireNonNull(supplier);
        Objects.requireNonNull(accumulator);
        Objects.requireNonNull(combiner);
        Objects.requireNonNull(characteristics);
        Set<Characteristics> cs = (characteristics.length == 0)
                                  ? Collectors.CH_ID
                                  : Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH,
                                                                           characteristics));
        return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, cs);
    }

    /**
     * Returns a new {@code Collector} described by the given {@code supplier},
     * {@code accumulator}, {@code combiner}, and {@code finisher} functions.
     *
     * @param supplier The supplier function for the new collector
     * @param accumulator The accumulator function for the new collector
     * @param combiner The combiner function for the new collector
     * @param finisher The finisher function for the new collector
     * @param characteristics The collector characteristics for the new
     *                        collector
     * @param <T> The type of input elements for the new collector
     * @param <A> The intermediate accumulation type of the new collector
     * @param <R> The final result type of the new collector
     * @throws NullPointerException if any argument is null
     * @return the new {@code Collector}
     */
    public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier,
                                                 BiConsumer<A, T> accumulator,
                                                 BinaryOperator<A> combiner,
                                                 Function<A, R> finisher,
                                                 Characteristics... characteristics) {
        Objects.requireNonNull(supplier);
        Objects.requireNonNull(accumulator);
        Objects.requireNonNull(combiner);
        Objects.requireNonNull(finisher);
        Objects.requireNonNull(characteristics);
        Set<Characteristics> cs = Collectors.CH_NOID;
        if (characteristics.length > 0) {
            cs = EnumSet.noneOf(Characteristics.class);
            Collections.addAll(cs, characteristics);
            cs = Collections.unmodifiableSet(cs);
        }
        return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, finisher, cs);
    }

    /**
     * Characteristics indicating properties of a {@code Collector}, which can
     * be used to optimize reduction implementations.
     */
    enum Characteristics {  // 特徵 
        /**
         * Indicates that this collector is <em>concurrent</em>, meaning that
         * the result container can support the accumulator function being
         * called concurrently with the same result container from multiple
         * threads.
         * 併發的,同一個結果容器能夠由多個線程同時調用。
         * <p>If a {@code CONCURRENT} collector is not also {@code UNORDERED},
         * then it should only be evaluated concurrently if applied to an
         * unordered data source.
若是不是UNORDERED。只能用於無序的數據源。 
若是不加CONCURRENT,仍是能夠操做並行流。可是操做的不是一個結果容器,而是多個結果容器。則須要調用finisher.
若是加了CONCURRENT,則是多個線程操做同一結果容器。 則無需調用finisher.
         */  
        CONCURRENT,   

        /**
         * Indicates that the collection operation does not commit to preserving
         * the encounter order of input elements.  (This might be true if the
         * result container has no intrinsic order, such as a {@link Set}.)
         收集操做並不保留順序。
         */
        UNORDERED,

        /**
         * Indicates that the finisher function is the identity function and
         * can be elided.  If set, it must be the case that an unchecked cast
         * from A to R will succeed.
        若是用和這個參數,表示 Finish函數就是 identity函數。 而且轉換必定要是成功的。
         */
        IDENTITY_FINISH
    }
}

Java8(4)(五)收集器比較器用法詳解及源碼剖析

收集器用法詳解與多級分組和分區

爲何在collectors類中定義一個靜態內部類?

static class CollectorImpl<T, A, R> implements Collector<T, A, R>

設計上,自己就是一個輔助類,是一個工廠。做用是給開發者提供常見的收集器實現。提供的方法都是靜態方法,能夠直接調用。

函數式編程最大的特色:表示作什麼,而不是如何作。開發者更注重如作什麼,底層實現如何作。

/**
 * Implementations of {@link Collector} that implement various useful reduction
 * operations, such as accumulating elements into collections, summarizing
 * elements according to various criteria, etc.
 
   沒有實現的方法,能夠本身去編寫收集器。
   
 * <p>The following are examples of using the predefined collectors to perform
 * common mutable reduction tasks:
 * 舉例: 
 * <pre>{@code
 *     // Accumulate names into a List   名字加入到一個集合。
 *     List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());
 *		
 *     // Accumulate names into a TreeSet  名字加入到一個Set。 待排序的集合。
 *     Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
 *
 *     // Convert elements to strings and concatenate them, separated by commas
 *     String joined = things.stream()
 *                           .map(Object::toString)
 *                           .collect(Collectors.joining(", "));
 *
 *     // Compute sum of salaries of employee	   計算員工工資的總數。
 *     int total = employees.stream()
 *                          .collect(Collectors.summingInt(Employee::getSalary)));
 *
 *     // Group employees by department    對員工進行分組。
 *     Map<Department, List<Employee>> byDept
 *         = employees.stream()
 *                    .collect(Collectors.groupingBy(Employee::getDepartment));
 *
 *     // Compute sum of salaries by department	   根據部門計算工資的總數。
 *     Map<Department, Integer> totalByDept
 *         = employees.stream()
 *                    .collect(Collectors.groupingBy(Employee::getDepartment,
 *                                                   Collectors.summingInt(Employee::getSalary)));
 *
 *     // Partition students into passing and failing    將學生進行分區。
 *     Map<Boolean, List<Student>> passingFailing =
 *         students.stream()
 *                 .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
 *
 * }</pre>
 *
 * @since 1.8    提供了常見的方法。沒有的話能夠去自定義。
 */
public final class Collectors {

舉例。collector中的方法應用:

public static void main(String[] args) {
        Student student1 = new Student("zhangsan", 80);
        Student student2 = new Student("lisi", 90);
        Student student3 = new Student("wangwu", 100);
        Student student4 = new Student("zhaoliu", 90);
        Student student5 = new Student("zhaoliu", 90);

        List<Student> students = Arrays.asList(student1, student2, student3, student4, student5);

        //list 轉換成一個流,再轉換成一個集合.
        List<Student> students1 = students.stream().collect(Collectors.toList());
        students1.forEach(System.out::println);
        System.out.println("- - - - - - -");

        // collect 方法底層原理介紹.

        //有多種方法能夠實現同一個功能.什麼方式更好呢? 越具體的方法越好.   減小自動裝箱拆箱操做.
        System.out.println("count:" + students.stream().collect(Collectors.counting()));
        System.out.println("count:" + (Long) students.stream().count());
        System.out.println("- - - -  - - - -");

        //舉例練習
        //  找出集合中分數最低的學生,打印出來.
        students.stream().collect(minBy(Comparator.comparingInt(Student::getScore))).ifPresent(System.out::println);
        //  找出集合中分數最大成績
        students.stream().collect(maxBy(Comparator.comparingInt(Student::getScore))).ifPresent(System.out::println);
        //  求平均值
        System.out.println(students.stream().collect(averagingInt(Student::getScore)));
        //  求分數的綜合
        System.out.println(students.stream().collect(summingInt(Student::getScore)));
        //  求各類彙總信息  結果爲IntSummaryStatistics{count=5, sum=450, min=80, average=90.000000, max=100}
        System.out.println(students.stream().collect(summarizingInt(Student::getScore)));

        System.out.println(" - - - - - ");
        // 字符串的拼接   結果爲:zhangsanlisiwangwuzhaoliuzhaoliu
        System.out.println(students.stream().map(Student::getName).collect(joining()));
        //拼接加分隔符    結果爲:zhangsan,lisi,wangwu,zhaoliu,zhaoliu
        System.out.println(students.stream().map(Student::getName).collect(joining(",")));
        // 拼接加先後綴   結果爲:hello  zhangsan,lisi,wangwu,zhaoliu,zhaoliu  world
        System.out.println(students.stream().map(Student::getName).collect(joining(",", "hello  ", "  world")));

        System.out.println("- - - - - - ");
        // group by 多層分組
        // 根據分數和名字進行分組  輸出結果爲:
        // {80={zhangsan=[Student{name='zhangsan', score=80}]},
        // 100={wangwu=[Student{name='wangwu', score=100}]},
        // 90={lisi=[Student{name='lisi', score=90}], zhaoliu=[Student{name='zhaoliu', score=90}, Student{name='zhaoliu', score=90}]}}
        Map<Integer, Map<String, List<Student>>> collect = students.stream().collect(groupingBy(Student::getScore, groupingBy(Student::getName)));
        System.out.println(collect);

        System.out.println("- - - - - - - ");
        // partitioningBy   多級分區   輸出結果爲:{false=[Student{name='zhangsan', score=80}], true=[Student{name='lisi', score=90}, Student{name='wangwu', score=100}, Student{name='zhaoliu', score=90}, Student{name='zhaoliu', score=90}]}
        Map<Boolean, List<Student>> collect1 = students.stream().collect(partitioningBy(student -> student.getScore() > 80));
        System.out.println(collect1);
        // 按照大於80分區,再按照90分區
        //輸出結果爲:{false={false=[Student{name='zhangsan', score=80}], true=[]}, true={false=[Student{name='lisi', score=90}, Student{name='zhaoliu', score=90}, Student{name='zhaoliu', score=90}], true=[Student{name='wangwu', score=100}]}}
        Map<Boolean, Map<Boolean, List<Student>>> collect2 = students.stream().collect(partitioningBy(student -> student.getScore() > 80, partitioningBy(student -> student.getScore() > 90)));
        System.out.println(collect2);

        //分區, 而後求出每一個分組中的個數.    結果爲:{false=1, true=4}
        Map<Boolean, Long> collect3 = students.stream().collect(partitioningBy(student -> student.getScore() > 80, counting()));
        System.out.println(collect3);

        System.out.println("- - - - - - - ");
        //根據名字分組,獲得學生的分數     --, 使用collectingAndThen 求最小值,而後整合起來. 最後Optional.get()必定有值.
        students.stream().collect(groupingBy(Student::getName,collectingAndThen(minBy(Comparator.comparingInt(Student::getScore)), Optional::get)));
    }

Comparator比較器詳解與類型推斷特例

Comparator 比較器。引用了多個default方法。

完成一個功能時有多個方法,使用特化的方法。由於效率會更高。減小了裝箱拆箱的操做。減小性能損耗。

舉例: 簡單功能實現

public static void main(String[] args) {
        List<String> list = Arrays.asList("nihao", "hello", "world", "welcome");

        //對list按照字母的升序排序
//        list.stream().sorted().forEach(System.out::println);

        //按照字符串的長度排序
//        Collections.sort(list, (item1, item2) -> item1.length() - item2.length());
//        Collections.sort(list, Comparator.comparingInt(String::length));

        //字符串的降序排序
//        list.sort(Comparator.comparingInt(String::length).reversed());

        // 下邊的形式會報錯   item識別成了(Obejct).
        //lambda表達式的類型推斷. 若是沒法推斷類型,須要本身制定類型
//        list.sort(Comparator.comparingInt(item-> item.length()).reversed());
        //這樣寫就成功了.
        list.sort(Comparator.comparingInt((String item )-> item.length()).reversed());

        //爲何這個地方沒法推斷類型?
        // 能推斷出的 :   list.stream()....    Strean<T>  傳遞的有參數.   精確的類型能夠進行類型推斷.
        //這個地方沒有明確具體是什麼類型.ToIntFunction<? super T>   .能夠是String 或者在往上的父類    這個地方當作了Object類了.

//        list.sort(Comparator.comparingInt((Boolean item)-> 1).reversed());
        //這種Boolean 就會報錯.編譯不經過.

        System.out.println(list);

    }

比較器深刻舉例練習

舉例:兩層的比較.先按照字符串的長度升序排序. 長度相同,根據每個ASCII碼的順序排序、

thenComparing()多級排序的練習。;

List<String> list = Arrays.asList("nihao", "hello", "world", "welcome");


//兩層的比較.先按照字符串的長度升序排序. 長度相同,根據每個ASCII碼的升序排序.     (不區分大小寫的 ,按照字母排序的規則)  幾種實現的方法。
    list.sort(Comparator.comparingInt(String::length).thenComparing(String.CASE_INSENSITIVE_ORDER));

list.sort(Comparator.comparingInt(String::length).thenComparing((item1,item2) -> item1.toUpperCase().compareTo(item2.toUpperCase())));
       list.sort(Comparator.comparingInt(String::length).thenComparing(Comparator.comparing(String::toUpperCase)));

//排序後將順序翻轉過來. reverseOrder();
list.sort(Comparator.comparingInt(String::length).thenComparing(String::toLowerCase,Comparator.reverseOrder()));

// 按照字符串的長度降序排序, 再根據ASCII的降序排序
list.sort(Comparator.comparingInt(String::length).reversed()
                .thenComparing(String::toLowerCase,Comparator.reverseOrder()));

//多級排序
list.sort(Comparator.comparingInt(String::length).reversed()
                .thenComparing(String::toLowerCase, Comparator.reverseOrder())
                .thenComparing(Comparator.reverseOrder())); 
 // 最後一個thenComparing()沒有發生做用。

自定義一個簡單的收集器

jdk提供了Collector接口。

public class MySetCollector<T>  implements Collector<T,Set<T>,Set<T>> {

    @Override
    public Supplier<Set<T>> supplier() {
        //用於提供一個空的容器
        System.out.println("supplier invoked! ");
        return HashSet::new;  // 不接受對象,返回一個Set對象
    }

    @Override
    public BiConsumer<Set<T>, T> accumulator() {
        // 累加器類型.   接收兩個參數不返回值.
        //完成的功能: 不斷的往set中添加元素
        System.out.println("accumulator invoked! ");
        return Set<T>::add ;
//        return HashSet<T>::add ;   返回HashSet報錯.  緣由: 返回的是中間類型的返回類型.  不論返回什麼類型的Set ,Set都符合要求.
    }

    @Override
    public BinaryOperator<Set<T>> combiner() {
        //將並行流的多個結果給合併起來.
        System.out.println("combiner invoked! ");
        return (set1,set2)->{
            set1.addAll(set2);
            return  set1;
        };
    }

    @Override
    public Function<Set<T>, Set<T>> finisher() {
        //完成器,把全部的結果都合併在一塊兒. 返回一個最終的結果類型
        //若是中間類型 和最終結果類型一致, 不執行此方法;
        System.out.println("finisher invoked! ");
//        return  t -> t ;
        return Function.identity(); // 老是返回參數.
    }

    @Override
    public Set<Characteristics> characteristics() {
        System.out.println("characterstics invoked! ");
        return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH,Characteristics.UNORDERED));  // 這個地方 不給參數,IDENTITY_FINISH  . 則會調用finisher()
    }

    public static void main(String[] args) {
        List<String> list = Arrays.asList("hello", "world");
        Set<String> collect = list.stream().collect(new MySetCollector<>());
        System.out.println(collect);
    }
  
  輸出結果爲: 
supplier invoked! 
accumulator invoked! 
combiner invoked! 
characterstics invoked! 
characterstics invoked! 
[world, hello]

}

接下來跟源碼,看一下程序的調用過程。

@Override
@SuppressWarnings("unchecked")
public final <R, A> R collect(Collector<? super P_OUT, A, R> collector) {
    A container;
    if (isParallel()
            && (collector.characteristics().contains(Collector.Characteristics.CONCURRENT))
            && (!isOrdered() || collector.characteristics().contains(Collector.Characteristics.UNORDERED))) {
        container = collector.supplier().get();
        BiConsumer<A, ? super P_OUT> accumulator = collector.accumulator();
        forEach(u -> accumulator.accept(container, u));
    }
    else {
        container = evaluate(ReduceOps.makeRef(collector));
    }
    return collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)
           ? (R) container
           : collector.finisher().apply(container);
}

自定義收集器的深度剖析與並行缺陷

// 舉例: 需求:將一個Set,進行一個收集.對結果進行加強,封裝在一個map當中.

// 輸入:Set<String>
// 輸出:Map<String,String>

// 示例輸入:   [hello,world,hello world]
// 示例輸出:  {[hello,hello],[world,world],[hello world,hello world]}
public class MySetCollector2<T> implements Collector<T, Set<T>, Map<T, T>> {
    @Override
    public Supplier<Set<T>> supplier() {
        System.out.println("supplier invoked!");
        return HashSet::new;
    }

    @Override
    public BiConsumer<Set<T>, T> accumulator() {
        System.out.println("accumlator invoked!");
        return (set, item) -> {
            set.add(item);
            //每次調用 打印出線程   這裏會打印6次,
            System.out.println("accunlator : " +set+ ", "+  Thread.currentThread().getName());
          
          //出現異常的緣由在這裏: 
// 一個線程去修改一個集合,同時另一個線程去迭代它(遍歷它)。程序就會拋出併發修改異常。若是是並行操做的話,就不要在操做中額外的添加操做。添加就添加,別再去打印他。 
        };
    }

    @Override
    public BinaryOperator<Set<T>> combiner() {
        System.out.println("combiner invoked!");
        //並行流的時候纔會被調用. 將並行流的多個結果給合併起來
        return (set1, set2) -> {
            set1.addAll(set2);
            return set2;
        };
    }

    @Override
    public Function<Set<T>, Map<T, T>> finisher() {
        System.out.println("finisher invoked!");
        // 中間類型和最終類型 同樣,這個是不會被調用的.
        //這裏不同 . 會進行調用

        return set -> {
            Map<T, T> map = new HashMap<>();
//            Map<T, T> map = new TreeMap<>();  直接返回一個排序的Map
            set.forEach(item -> map.put(item,item));
            return map;
        };
    }

    @Override
    public Set<Characteristics> characteristics() {
        System.out.println(" characteristics invoked");

        return Collections.unmodifiableSet(EnumSet.of(Characteristics.UNORDERED));// 這個參數不能亂寫. 要理解每一個枚舉的具體意思.

//        return Collections.unmodifiableSet(EnumSet.of(Characteristics.UNORDERED,Characteristics.CONCURRENT));// 這個參數不能亂寫. 要理解每一個枚舉的具體意思.
        //加了這個參數 Characteristics.CONCURRENT
        //  會出異常, 會正常運行.  Caused by: java.util.ConcurrentModificationException

//        return Collections.unmodifiableSet(EnumSet.of(Characteristics.UNORDERED,Characteristics.IDENTITY_FINISH));
        // 加了參數Characteristics.IDENTITY_FINISH .  會報錯
        // Process 'command '/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/bin/java'' finished with non-zero exit value 1

        // IDENTITY_FINISH 實際的含義: 若是用和這個參數,表示 Finish函數就是 identity函數。 而且轉換必定要是成功的。失敗的話會拋異常.
        // 這個收集器具備什麼特性 ,由Characteristics 來定義. 就算你賦值的不實際,他也照樣執行.
    }

    public static void main(String[] args) {
        List<String> list = Arrays.asList("hello","hello", "world", "helloworld","1","4","j");
        Set<String> set = new HashSet<>(list);

        System.out.println("set"+set);

//        Map<String, String> collect = set.stream().collect(new MySetCollector2<>());
        Map<String, String> collect = set.parallelStream().collect(new MySetCollector2<>());  //並行流
        System.out.println(collect);
    }
}

並行流缺陷詳解

並行: 
accumlator invoked!
accunlator : [j], main
accunlator : [j, hello], main
accunlator : [helloworld, 4, j, hello], ForkJoinPool.commonPool-worker-2
accunlator : [helloworld, 1, 4, j, hello], ForkJoinPool.commonPool-worker-2
accunlator : [helloworld, 1, world, 4, j, hello], ForkJoinPool.commonPool-worker-2
串行。
accunlator : [j], main
accunlator : [helloworld], ForkJoinPool.commonPool-worker-11
accunlator : [helloworld, 1], ForkJoinPool.commonPool-worker-11
accunlator : [helloworld, 1, world], ForkJoinPool.commonPool-worker-11
accunlator : [4], ForkJoinPool.commonPool-worker-9
accunlator : [j, hello], main
/**
     * Characteristics indicating properties of a {@code Collector}, which can
     * be used to optimize reduction implementations.
     */
    enum Characteristics {  // 特徵 
        /**
         * Indicates that this collector is <em>concurrent</em>, meaning that
         * the result container can support the accumulator function being
         * called concurrently with the same result container from multiple
         * threads.
         * 併發的,同一個結果容器能夠由多個線程同時調用。
         * <p>If a {@code CONCURRENT} collector is not also {@code UNORDERED},
         * then it should only be evaluated concurrently if applied to an
         * unordered data source.
若是不是UNORDERED。只能用於無序的數據源。 
若是不加CONCURRENT,仍是能夠操做並行流。可是操做的不是一個結果容器,而是多個結果容器。則須要調用finisher.
若是加了CONCURRENT,則是多個線程操做同一結果容器。 則無需調用finisher.
         */  
        CONCURRENT,   

        /**
         * Indicates that the collection operation does not commit to preserving
         * the encounter order of input elements.  (This might be true if the
         * result container has no intrinsic order, such as a {@link Set}.)
         收集操做並不保留順序。無序的。
         */
        UNORDERED,

        /**
         * Indicates that the finisher function is the identity function and
         * can be elided.  If set, it must be the case that an unchecked cast
         * from A to R will succeed.
        若是用和這個參數,表示 Finish函數就是 identity函數。 而且轉換必定要是成功的。不會調用Finish方法
         */
        IDENTITY_FINISH
    }

出異常的根本緣由:

一個線程去修改一個集合,同時另一個線程去迭代它(遍歷它)。程序就會拋出併發修改異常。

若是是並行操做的話,就不要在操做中額外的添加操做。添加就添加,別再去打印他。

若是不加CONCURRENT,仍是能夠操做並行流。可是操做的不是一個結果容器,而是多個結果容器。則須要調用finisher. 若是加了CONCURRENT,則是多個線程操做同一結果容器。 則無需調用finisher.

超線程介紹:

超線程(HT, Hyper-Threading)是英特爾研發的一種技術,於2002年發佈。超線程技術原先只應用於Xeon 處理器中,當時稱爲「Super-Threading」。以後陸續應用在Pentium 4 HT中。早期代號爲Jackson。 [1]

經過此技術,英特爾實如今一個實體CPU中,提供兩個邏輯線程。以後的[Pentium D](https://baike.baidu.com/item/Pentium D)縱使不支持超線程技術,但就集成了兩個實體核心,因此仍會見到兩個線程。超線程的將來發展,是提高處理器的邏輯線程。英特爾於2016年發佈的Core i7-6950X即是將10核心的處理器,加上超線程技術,使之成爲20個邏輯線程的產品

收集器總結:

Collectors類中方法的實現練習。收集器老是有中間的容器。有必要的總結一下收集器中的方法。

當你具有一些前提的東西以後,你再去看難的東西就會以爲理所固然的。

對於Collectors靜態工廠類來講,實現一共分爲兩種狀況:

  1. 經過CollectorImpl來實現。

  2. 經過reducing方法來實現;reducing方法自己又是經過CollectorImpl實現的。

    總的來講,都是經過CollectorImpl來實現的。

1. toCollection(collectionFactory) 。  將集合轉成指定的集合。
public static <T, C extends Collection<T>>
Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) {
    return new CollectorImpl<>(collectionFactory, Collection<T>::add,
                               (r1, r2) -> { r1.addAll(r2); return r1; },
                               CH_ID);
}
2. toList()是 toCollection()方法的一種具體實現。
public static <T>
Collector<T, ?, List<T>> toList() {
    return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
                               (left, right) -> { left.addAll(right); return left; },
                               CH_ID);
}
3. toSet() 是toCollection()方法的一種具體實現。
public static <T>
Collector<T, ?, Set<T>> toSet() {
    return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add,
                               (left, right) -> { left.addAll(right); return left; },
                               CH_UNORDERED_ID);
}
4. joining(); 融合成一個字符串。還有兩個重載的,單參數的和多參數的
public static Collector<CharSequence, ?, String> joining() {
    return new CollectorImpl<CharSequence, StringBuilder, String>(
            StringBuilder::new, StringBuilder::append,
            (r1, r2) -> { r1.append(r2); return r1; },
            StringBuilder::toString, CH_NOID);
}

public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) {
        return joining(delimiter, "", "");
    }

public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,
                                                             CharSequence prefix,
                                                             CharSequence suffix) {
        return new CollectorImpl<>(
                () -> new StringJoiner(delimiter, prefix, suffix),
                StringJoiner::add, StringJoiner::merge,
                StringJoiner::toString, CH_NOID);
    }
5.mapping(); 將收集器的A 映射成B 
public static <T, U, A, R>
Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper,
                           Collector<? super U, A, R> downstream) {
    BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
    return new CollectorImpl<>(downstream.supplier(),
                               (r, t) -> downstreamAccumulator.accept(r, mapper.apply(t)),
                               downstream.combiner(), downstream.finisher(),
                               downstream.characteristics());
}

such as :
Map<City, Set<String>> lastNamesByCity
  = people.stream().collect(groupingBy(Person::getCity, mapping(Person::getLastName, toSet())));
6.collectingAndThen(); 收集處理轉換完後, 再去進行一個轉換。
public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream,
                                                            Function<R,RR> finisher) {
    Set<Collector.Characteristics> characteristics = downstream.characteristics();
    if (characteristics.contains(Collector.Characteristics.IDENTITY_FINISH)) {
        if (characteristics.size() == 1)
            characteristics = Collectors.CH_NOID;
        else {
            characteristics = EnumSet.copyOf(characteristics);
            characteristics.remove(Collector.Characteristics.IDENTITY_FINISH);
           // 這個地方爲何要把IDENTITY_FINISH 去掉。
          // 若是不去掉的話, 最終結果直接返回中間結果的類型
            characteristics = Collections.unmodifiableSet(characteristics);
        }
    }
    return new CollectorImpl<>(downstream.supplier(),
                               downstream.accumulator(),
                               downstream.combiner(),
                               downstream.finisher().andThen(finisher),
                               characteristics);
}

such as : 
 List<String> people
       = people.stream().collect(collectingAndThen(toList(),Collections::unmodifiableList));
7. counting(); 計數。
public static <T> Collector<T, ?, Long>
counting() {
    return reducing(0L, e -> 1L, Long::sum);
}
8. 最大值最小值  
    public static <T> Collector<T, ?, Optional<T>>
    minBy(Comparator<? super T> comparator) {
        return reducing(BinaryOperator.minBy(comparator));
    }
 public static <T> Collector<T, ?, Optional<T>>
    maxBy(Comparator<? super T> comparator) {
        return reducing(BinaryOperator.maxBy(comparator));
    }
9. summingInt();求和。
public static <T> Collector<T, ?, Integer>
summingInt(ToIntFunction<? super T> mapper) {
    return new CollectorImpl<>(
            () -> new int[1],   // 這個地方爲何不能夠用一個0,來當作中間類型呢?數字自己是一個值類型的,不可變的,無法引用。數組自己是一個引用類型,能夠進行傳遞。數組自己是一個容器。      								
            (a, t) -> { a[0] += mapper.applyAsInt(t); },
            (a, b) -> { a[0] += b[0]; return a; },
            a -> a[0], CH_NOID);
}

public static <T> Collector<T, ?, Long>
    summingLong(ToLongFunction<? super T> mapper) {
        return new CollectorImpl<>(
                () -> new long[1],
                (a, t) -> { a[0] += mapper.applyAsLong(t); },
                (a, b) -> { a[0] += b[0]; return a; },
                a -> a[0], CH_NOID);
    }

public static <T> Collector<T, ?, Double>
    summingDouble(ToDoubleFunction<? super T> mapper) {
        /*
         * In the arrays allocated for the collect operation, index 0
         * holds the high-order bits of the running sum, index 1 holds
         * the low-order bits of the sum computed via compensated
         * summation, and index 2 holds the simple sum used to compute
         * the proper result if the stream contains infinite values of
         * the same sign.
         */
        return new CollectorImpl<>(
                () -> new double[3],  
                (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t));
                            a[2] += mapper.applyAsDouble(t);},
                (a, b) -> { sumWithCompensation(a, b[0]);
                            a[2] += b[2];
                            return sumWithCompensation(a, b[1]); },
                a -> computeFinalSum(a),
                CH_NOID);
    }
10. averagingInt(); 求平均值。
public static <T> Collector<T, ?, Double>
averagingInt(ToIntFunction<? super T> mapper) {
    return new CollectorImpl<>(
            () -> new long[2],
            (a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; },
            (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
            a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
}

public static <T> Collector<T, ?, Double>
    averagingLong(ToLongFunction<? super T> mapper) {
        return new CollectorImpl<>(
                () -> new long[2],
                (a, t) -> { a[0] += mapper.applyAsLong(t); a[1]++; },
                (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
                a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
    }
public static <T> Collector<T, ?, Double>
    averagingDouble(ToDoubleFunction<? super T> mapper) {
        /*
         * In the arrays allocated for the collect operation, index 0
         * holds the high-order bits of the running sum, index 1 holds
         * the low-order bits of the sum computed via compensated
         * summation, and index 2 holds the number of values seen.
         */
        return new CollectorImpl<>(
                () -> new double[4],
                (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); a[2]++; a[3]+= mapper.applyAsDouble(t);},
                (a, b) -> { sumWithCompensation(a, b[0]); sumWithCompensation(a, b[1]); a[2] += b[2]; a[3] += b[3]; return a; },
                a -> (a[2] == 0) ? 0.0d : (computeFinalSum(a) / a[2]),
                CH_NOID);
    }
11.  reducing() ; 詳解。
public static <T> Collector<T, ?, T>
    reducing(T identity, BinaryOperator<T> op) {
        return new CollectorImpl<>(
                boxSupplier(identity),
                (a, t) -> { a[0] = op.apply(a[0], t); },
                (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; },
                a -> a[0],
                CH_NOID);
    }
12. groupingBy(); 分組方法詳解。
public static <T, K> Collector<T, ?, Map<K, List<T>>> 	//使用者自己不注重中間類型怎麼操做。
groupingBy(Function<? super T, ? extends K> classifier) {  
    return groupingBy(classifier, toList());   //調用兩個參數的 groupingBy();
}

 * @param <T> the type of the input elements   //T; 接收的類型。
     * @param <K> the type of the keys	//  K,分類器函數中間返回結果的類型。
     * @param <A> the intermediate accumulation type of the downstream collector
     * @param <D> the result type of the downstream reduction
 *
public static <T, K, A, D>  
    Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
                                          Collector<? super T, A, D> downstream) {
        return groupingBy(classifier, HashMap::new, downstream); // 調用三參數的 groupingBy()
    }

//功能最徹底的groupingBy();

    /**
     * Returns a {@code Collector} implementing a cascaded "group by" operation
     * on input elements of type {@code T}, grouping elements according to a
     * classification function, and then performing a reduction operation on
     * the values associated with a given key using the specified downstream
     * {@code Collector}.  The {@code Map} produced by the Collector is created
     * with the supplied factory function.
     *
     * <p>The classification function maps elements to some key type {@code K}.
     * The downstream collector operates on elements of type {@code T} and
     * produces a result of type {@code D}. The resulting collector produces a
     * {@code Map<K, D>}.
     *
     * <p>For example, to compute the set of last names of people in each city,
     * where the city names are sorted:
     * <pre>{@code
     *     Map<City, Set<String>> namesByCity
     *         = people.stream().collect(groupingBy(Person::getCity, TreeMap::new,
     *                                              mapping(Person::getLastName, toSet())));
     * }</pre>
     *
     * @implNote
     * The returned {@code Collector} is not concurrent.  For parallel stream
     * pipelines, the {@code combiner} function operates by merging the keys
     * from one map into another, which can be an expensive operation.  If
     * preservation of the order in which elements are presented to the downstream
     * collector is not required, using {@link #groupingByConcurrent(Function, Supplier, Collector)}
     * may offer better parallel performance.
     *  返回的 並非併發的。若是順序並非很重要的話, 推薦使用groupingByConcurrent(); 併發的分組函數。
     * @param <T> the type of the input elements
     * @param <K> the type of the keys
     * @param <A> the intermediate accumulation type of the downstream collector
     * @param <D> the result type of the downstream reduction
     * @param <M> the type of the resulting {@code Map}
     * @param classifier a classifier function mapping input elements to keys
     * @param downstream a {@code Collector} implementing the downstream reduction
     * @param mapFactory a function which, when called, produces a new empty
     *                   {@code Map} of the desired type
     * @return a {@code Collector} implementing the cascaded group-by operation
     *
     * @see #groupingBy(Function, Collector)
     * @see #groupingBy(Function)
     * @see #groupingByConcurrent(Function, Supplier, Collector)
     */
public static <T, K, D, A, M extends Map<K, D>>  
    Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,
                                  Supplier<M> mapFactory,
                                  Collector<? super T, A, D> downstream) {
        Supplier<A> downstreamSupplier = downstream.supplier();
        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
        BiConsumer<Map<K, A>, T> accumulator = (m, t) -> {
            K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
            A container = m.computeIfAbsent(key, k -> downstreamSupplier.get());
            downstreamAccumulator.accept(container, t); 
        };
        BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstream.combiner());  //接收兩個參數,參會一個結果。
        @SuppressWarnings("unchecked")
        Supplier<Map<K, A>> mangledFactory = (Supplier<Map<K, A>>) mapFactory; // 進行一個強制的類型轉換。

        if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {       
         //若是 IDENTITY_FINISH , 則不用調用finisher方法。
           return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID);
        }
        else {
            @SuppressWarnings("unchecked")
            Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
            Function<Map<K, A>, M> finisher = intermediate -> {
                intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
                @SuppressWarnings("unchecked")
                M castResult = (M) intermediate;
                return castResult;
            };
            return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID);
        }
    }
13. groupingByConcurrent(); 併發的分組方法。 使用前提是對數據裏邊的順序沒有要求。
   /**
     * Returns a concurrent {@code Collector} implementing a cascaded "group by"
     * operation on input elements of type {@code T}, grouping elements
     * according to a classification function, and then performing a reduction
     * operation on the values associated with a given key using the specified
     * downstream {@code Collector}.
     */			//  ConcurrentHashMap    是一個支持併發的Map 
  public static <T, K>
    Collector<T, ?, ConcurrentMap<K, List<T>>>
    groupingByConcurrent(Function<? super T, ? extends K> classifier) {
        return groupingByConcurrent(classifier, ConcurrentHashMap::new, toList());
    }

 public static <T, K, A, D>
    Collector<T, ?, ConcurrentMap<K, D>> groupingByConcurrent(Function<? super T, ? extends K> classifier,
                                                              Collector<? super T, A, D> downstream) {
        return groupingByConcurrent(classifier, ConcurrentHashMap::new, downstream);
    }

 public static <T, K, A, D, M extends ConcurrentMap<K, D>>
    Collector<T, ?, M> groupingByConcurrent(Function<? super T, ? extends K> classifier,
                                            Supplier<M> mapFactory,
                                            Collector<? super T, A, D> downstream) {
        Supplier<A> downstreamSupplier = downstream.supplier();
        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
        BinaryOperator<ConcurrentMap<K, A>> merger = Collectors.<K, A, ConcurrentMap<K, A>>mapMerger(downstream.combiner());
        @SuppressWarnings("unchecked")
        Supplier<ConcurrentMap<K, A>> mangledFactory = (Supplier<ConcurrentMap<K, A>>) mapFactory;
        BiConsumer<ConcurrentMap<K, A>, T> accumulator;
        if (downstream.characteristics().contains(Collector.Characteristics.CONCURRENT)) {
            accumulator = (m, t) -> {
                K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
                A resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get());
                downstreamAccumulator.accept(resultContainer, t);
            };
        }
        else {
            accumulator = (m, t) -> {
                K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
                A resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get());
                synchronized (resultContainer) {  // 這裏有一個同步的操做。雖然是多線程操做同一容器,可是同時仍是隻有一個線程操做,進行了同步。
                    downstreamAccumulator.accept(resultContainer, t);
                }
            };
        }

        if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
            return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_CONCURRENT_ID);
        }
        else {
            @SuppressWarnings("unchecked")
            Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
            Function<ConcurrentMap<K, A>, M> finisher = intermediate -> {
                intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
                @SuppressWarnings("unchecked")
                M castResult = (M) intermediate;
                return castResult;
            };
            return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_CONCURRENT_NOID);
        }
    }
14. partitioningBy(); 分區詳解。
public static <T>
Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) {
    return partitioningBy(predicate, toList());
}

public static <T, D, A>
    Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,
                                                    Collector<? super T, A, D> downstream) {
        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
        BiConsumer<Partition<A>, T> accumulator = (result, t) ->
                downstreamAccumulator.accept(predicate.test(t) ? result.forTrue : result.forFalse, t);
        BinaryOperator<A> op = downstream.combiner();
        BinaryOperator<Partition<A>> merger = (left, right) ->
                new Partition<>(op.apply(left.forTrue, right.forTrue),
                                op.apply(left.forFalse, right.forFalse));
        Supplier<Partition<A>> supplier = () ->
                new Partition<>(downstream.supplier().get(),
                                downstream.supplier().get());
        if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
            return new CollectorImpl<>(supplier, accumulator, merger, CH_ID);
        }
        else {
            Function<Partition<A>, Map<Boolean, D>> finisher = par ->
                    new Partition<>(downstream.finisher().apply(par.forTrue),
                                    downstream.finisher().apply(par.forFalse));
            return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID);
        }
    }

jdk的代碼,就是咱們學習的範本。

講這麼細的緣由並非由於要本身去寫,是爲了瞭解內部是具體怎麼實現的。調用的時候就信心很是的足。

附一個小插曲。

image-20200105201926874

Java8(5)Stream流源碼詳解

節前小插曲

AutoCloseable接口: 經過一個例子 舉例自動關閉流的實現。

public interface BaseStream<T, S extends BaseStream<T, S>>
        extends AutoCloseable{}  // BaseStream 繼承了這個接口。 Stream繼承了Stream
public class AutoCloseableTest implements AutoCloseable {
    public void dosomething() {
        System.out.println(" do something ");
    }

    @Override
    public void close() throws Exception {
        System.out.println(" close invoked ");
    }

    public static void main(String[] args) throws Exception {
        try ( AutoCloseableTest autoCloseableTest = new AutoCloseableTest()){
            autoCloseableTest.dosomething();
        }
    }
}

運行結果以下: 自動調用了關閉流的方法

image-20200105211344897

Stream

/**
 * A sequence of elements supporting sequential and parallel aggregate
 * operations.  The following example illustrates an aggregate operation using
 * {@link Stream} and {@link IntStream}:
 *
 * <pre>{@code   // 舉例: 
 *     int sum = widgets.stream()
 *                      .filter(w -> w.getColor() == RED)
 *                      .mapToInt(w -> w.getWeight())
 *                      .sum();
 * }</pre>
 *
 * In this example, {@code widgets} is a {@code Collection<Widget>}.  We create
 * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
 * filter it to produce a stream containing only the red widgets, and then
 * transform it into a stream of {@code int} values representing the weight of
 * each red widget. Then this stream is summed to produce a total weight.
 *
 * <p>In addition to {@code Stream}, which is a stream of object references,
 * there are primitive specializations for {@link IntStream}, {@link LongStream},
 * and {@link DoubleStream}, all of which are referred to as "streams" and
 * conform to the characteristics and restrictions described here.
 jdk提供了平行的 特化的流。
 *
 * <p>To perform a computation, stream
 * <a href="package-summary.html#StreamOps">operations</a> are composed into a
 * <em>stream pipeline</em>.  A stream pipeline consists of a source (which
 * might be an array, a collection, a generator function, an I/O channel,
 * etc), zero or more <em>intermediate operations</em> (which transform a
 * stream into another stream, such as {@link Stream#filter(Predicate)}), and a
 * <em>terminal operation</em> (which produces a result or side-effect, such
 * as {@link Stream#count()} or {@link Stream#forEach(Consumer)}).
 * Streams are lazy; computation on the source data is only performed when the
 * terminal operation is initiated, and source elements are consumed only
 * as needed.
 
 
 爲了執行計算,流會被執行到一個流管道當中。
 一個流管道包含了:
 一個源。(數字來的地方)
 0個或多箇中間操做(將一個stream轉換成另一個Stream)。
 一個終止操做(會生成一個結果,或者是一個反作用(求和,遍歷))。
 
 流是延遲的,只有當終止操做被髮起的時候,纔會執行中間操做。
 
 * <p>Collections and streams, while bearing some superficial similarities,
 * have different goals.  Collections are primarily concerned with the efficient
 * management of, and access to, their elements.  By contrast, streams do not
 * provide a means to directly access or manipulate their elements, and are
 * instead concerned with declaratively describing their source and the
 * computational operations which will be performed in aggregate on that source.
 * However, if the provided stream operations do not offer the desired
 * functionality, the {@link #iterator()} and {@link #spliterator()} operations
 * can be used to perform a controlled traversal.
 
 集合和流雖然有一些類似性,可是他們的差別是不一樣的。
 集合是爲了高效對於元素的管理和訪問。流並不會提供方式去直接操做流裏的元素。(集合關注的是數據的管理,流關注的是元素內容的計算)
 若是流操做並無提供咱們須要的功能,那麼咱們可使用傳統的iterator or spliterator去執行操做。 

 * <p>A stream pipeline, like the "widgets" example above, can be viewed as
 * a <em>query</em> on the stream source.  Unless the source was explicitly
 * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
 * unpredictable or erroneous behavior may result from modifying the stream
 * source while it is being queried.
 
 一個流管道,能夠看作是對流源的查詢,除非這個流被顯示的設計成能夠併發修改的。不然會拋出異常。
 (如一個線程對流進行修改,另外一個對流進行查詢)
 
 * <p>Most stream operations accept parameters that describe user-specified
 * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
 * {@code mapToInt} in the example above.  To preserve correct behavior,
 * these <em>behavioral parameters</em>:
	//爲了能知足結果,需知足下邊的條件。
 * <ul>
 * <li>must be <a href="package-summary.html#NonInterference">non-interfering</a>
 * (they do not modify the stream source); and</li>
 * <li>in most cases must be <a href="package-summary.html#Statelessness">stateless</a>
 * (their result should not depend on any state that might change during execution
 * of the stream pipeline).</li>
 * </ul>
 
 行爲上的參數,大可能是無狀態的。
 
 * <p>Such parameters are always instances of a
 * <a href="../function/package-summary.html">functional interface</a> such
 * as {@link java.util.function.Function}, and are often lambda expressions or
 * method references.  Unless otherwise specified these parameters must be
 * <em>non-null</em>.
 
	無一例外的。這種參數老是函數式接口的形式。也就是lambda表達式。除非特別指定,這些參數必須是非空的。
	
 * <p>A stream should be operated on (invoking an intermediate or terminal stream
 * operation) only once.  This rules out, for example, "forked" streams, where
 * the same source feeds two or more pipelines, or multiple traversals of the
 * same stream.  A stream implementation may throw {@link IllegalStateException}
 * if it detects that the stream is being reused. However, since some stream
 * operations may return their receiver rather than a new stream object, it may
 * not be possible to detect reuse in all cases.
 
 一個流只能被使用一次。對相同的流進行屢次操做,須要建立多個流管道。
 
 * <p>Streams have a {@link #close()} method and implement {@link AutoCloseable},
 * but nearly all stream instances do not actually need to be closed after use.
 * Generally, only streams whose source is an IO channel (such as those returned
 * by {@link Files#lines(Path, Charset)}) will require closing.  Most streams
 * are backed by collections, arrays, or generating functions, which require no
 * special resource management.  (If a stream does require closing, it can be
 * declared as a resource in a {@code try}-with-resources statement.)
 
 流擁有一個closed方法,實現了AutoCloseable,在他的父類裏。 最上面以舉例實現。
 可是一個流 除了是I/O流(由於持有句柄等資源)才須要被關閉外,是不須要被關閉的。
 大多數的流底層是集合、數組或者是生成器函數。 他們並不須要特別的資源管理。若是須要被關閉,能夠用try()操做。

 * <p>Stream pipelines may execute either sequentially or in
 * <a href="package-summary.html#Parallelism">parallel</a>.  This
 * execution mode is a property of the stream.  Streams are created
 * with an initial choice of sequential or parallel execution.  (For example,
 * {@link Collection#stream() Collection.stream()} creates a sequential stream,
 * and {@link Collection#parallelStream() Collection.parallelStream()} creates
 * a parallel one.)  This choice of execution mode may be modified by the
 * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
 * the {@link #isParallel()} method.
 
 流管道能夠被串行或者並行操做。這種模式只是一個屬性而已。 初始化的時候會進行一個選擇。
 好比說  stream() 是串行流。parallelStream()是並行流。 
 還能夠經過sequential()or parallel() 來進行修改。 以最後一個被調用的方法爲準。
 也能夠用isParallel()來進行查詢流是不是並行流。
 
 * @param <T> the type of the stream elements
 * @since 1.8
 * @see IntStream
 * @see LongStream
 * @see DoubleStream
 * @see <a href="package-summary.html">java.util.stream</a>
 */
public interface Stream<T> extends BaseStream<T, Stream<T>> {
  
  // 具體舉例, 源碼中有例子
	Stream<T> filter(Predicate<? super T> predicate);    // 過濾
  <R> Stream<R> map(Function<? super T, ? extends R> mapper);  //映射
  IntStream mapToInt(ToIntFunction<? super T> mapper);
  LongStream mapToLong(ToLongFunction<? super T> mapper);
  DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper); 
  <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper); //壓平
  IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
  LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
  DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);、
  Stream<T> distinct();// 去重
  Stream<T> sorted(); //排序
  Stream<T> sorted(Comparator<? super T> comparator);
  Stream<T> peek(Consumer<? super T> action);  
  Stream<T> limit(long maxSize);  // 截斷
  void forEach(Consumer<? super T> action); // 遍歷
  void forEachOrdered(Consumer<? super T> action); // 遍歷時執行操做
  Object[] toArray();  // 轉數組
  T reduce(T identity, BinaryOperator<T> accumulator); //  匯聚, 返回一個匯聚的結果
  <R> R collect(Supplier<R> supplier,
                  BiConsumer<R, ? super T> accumulator,
                  BiConsumer<R, R> combiner);     // 收集器 
  。。。  
}

自行參考父接口中的方法;


Stream中具體方法的詳解

分割迭代器:

/**

 * Returns a spliterator for the elements of this stream.
 *
 * <p>This is a <a href="package-summary.html#StreamOps">terminal
 * operation</a>.
 *
 * @return the element spliterator for this stream
 */
Spliterator<T> spliterator();

Java8(6)spliterator及baseStream 源碼講解

在公司的學習筆記。

baseStream 源碼講解

BaseStream 是全部流的父類 。

/**
 * Base interface for streams, which are sequences of elements supporting
 * sequential and parallel aggregate operations.  The following example
 * illustrates an aggregate operation using the stream types {@link Stream}
 * and {@link IntStream}, computing the sum of the weights of the red widgets:
 *
 * <pre>{@code
 *     int sum = widgets.stream()
 *                      .filter(w -> w.getColor() == RED)
 *                      .mapToInt(w -> w.getWeight())
 *                      .sum();
 * }</pre>
 *
 * See the class documentation for {@link Stream} and the package documentation
 * for <a href="package-summary.html">java.util.stream</a> for additional
 * specification of streams, stream operations, stream pipelines, and
 * parallelism, which governs the behavior of all stream types.
 *
 * @param <T> the type of the stream elements
 * @param <S> the type of of the stream implementing {@code BaseStream}
 * @since 1.8
 * @see Stream
 * @see IntStream
 * @see LongStream
 * @see DoubleStream
 * @see <a href="package-summary.html">java.util.stream</a>
 */
public interface BaseStream<T, S extends BaseStream<T, S>> extends AutoCloseable 

public interface Stream<T> extends BaseStream<T, Stream<T>>
BaseStream(){

 Iterator<T> iterator(); 迭代器
 Spliterator<T> spliterator();  分割迭代器  。 這是一個流的終止操做。
 boolean isParallel();  是不是並行。   
 S sequential();  // 返回一個等價的串行流。   返回S是一個新的流對象
 S parallel();   //返回一個並行流。 
 S unordered();   // 返回一個無序的流。
 S onClose(Runnable closeHandler);   //當前流.onClose、 當close調用時,調用此方法。
 void close();      // 關閉流
 
 }

關閉處理器的舉例

/**
     * Returns an equivalent stream with an additional close handler.  Close
     * handlers are run when the {@link #close()} method
     * is called on the stream, and are executed in the order they were
     * added.  All close handlers are run, even if earlier close handlers throw
     * exceptions.  If any close handler throws an exception, the first
     * exception thrown will be relayed to the caller of {@code close()}, with
     * any remaining exceptions added to that exception as suppressed exceptions
     * (unless one of the remaining exceptions is the same exception as the
     * first exception, since an exception cannot suppress itself.)  May
     * return itself.
     *
     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
     * operation</a>.
     *
     * @param closeHandler A task to execute when the stream is closed
     * @return a stream with a handler that is run if the stream is closed
     */
    S onClose(Runnable closeHandler);
public static void main(String[] args) {

        List<String> list = Arrays.asList("hello","world");
        NullPointerException nullPointerException = new NullPointerException("myexception");
        try (Stream<String> stream = list.stream()){
            stream.onClose(()->{
                System.out.println("aaa");
//                throw new NullPointerException("first");
                throw nullPointerException;
            }).onClose(()->{
                System.out.println("aaa");
                throw nullPointerException;
            }).forEach(System.out::println);
        }
        // 出現異常會被壓制,
        // 若是是同一個異常對象,只會打印一次異常。 若是是多個異常對象。都會被打印。
    }

javadoc 中的介紹比任何資料都詳細。


Stream 源碼分析。

stream();

/**
     * Returns a sequential {@code Stream} with this collection as its source.
     
     返回一個串行流,把這個集合當作源
     
     * <p>This method should be overridden when the {@link #spliterator()}
     * method cannot return a spliterator that is {@code IMMUTABLE},
     * {@code CONCURRENT}, or <em>late-binding</em>. (See {@link #spliterator()}
     * for details.)

     當不能返回  三種方法 中的一個時,這個方法應該被重寫。
     
     * @implSpec
     * The default implementation creates a sequential {@code Stream} from the
     * collection's {@code Spliterator}.
     
     默認會從集合中建立一個串行流。 返回
     
     * @return a sequential {@code Stream} over the elements in this collection
     * @since 1.8
     */
    default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    }

spliterator(); 分割迭代器

/**
     * Creates a {@link Spliterator} over the elements in this collection.
     *
     * Implementations should document characteristic values reported by the
     * spliterator.  Such characteristic values are not required to be reported
     * if the spliterator reports {@link Spliterator#SIZED} and this collection
     * contains no elements.
     
     * <p>The default implementation should be overridden by subclasses that
     * can return a more efficient spliterator.  In order to
     * preserve expected laziness behavior for the {@link #stream()} and
     * {@link #parallelStream()}} methods, spliterators should either have the
     * characteristic of {@code IMMUTABLE} or {@code CONCURRENT}, or be
     * <em><a href="Spliterator.html#binding">late-binding</a></em>.
     
     默認的子類應該被重寫。爲了保留parallelStream  和 stream的延遲行爲。特性須要知足IMMUTABLE 或者CONCURRENT
     
     * If none of these is practical, the overriding class should describe the
     * spliterator's documented policy of binding and structural interference,
     * and should override the {@link #stream()} and {@link #parallelStream()}
     * methods to create streams using a {@code Supplier} of the spliterator,
     * as in:
     * <pre>{@code
     *     Stream<E> s = StreamSupport.stream(() -> spliterator(), spliteratorCharacteristics)
     * }</pre>
     
     爲何叫分割迭代器。先分割,在迭代。
     若是不能知足上述的要求,則重寫的時候應該知足上述的需求、
     
     * <p>These requirements ensure that streams produced by the
     * {@link #stream()} and {@link #parallelStream()} methods will reflect the
     * contents of the collection as of initiation of the terminal stream
     * operation.
     
     這些確保了流會返回的內容。
     
     * @implSpec
     * The default implementation creates a
     * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
     * from the collections's {@code Iterator}.  The spliterator inherits the
     * <em>fail-fast</em> properties of the collection's iterator.
     * <p>
     * The created {@code Spliterator} reports {@link Spliterator#SIZED}.
    
     默認會從集合的迭代器中建立出一個延遲的分割迭代器。 默認的迭代器 會有默認大小的迭代器。
     
     * @implNote
     * The created {@code Spliterator} additionally reports
     * {@link Spliterator#SUBSIZED}.
     *
     * <p>If a spliterator covers no elements then the reporting of additional
     * characteristic values, beyond that of {@code SIZED} and {@code SUBSIZED},
     * does not aid clients to control, specialize or simplify computation.
     * However, this does enable shared use of an immutable and empty
     * spliterator instance (see {@link Spliterators#emptySpliterator()}) for
     * empty collections, and enables clients to determine if such a spliterator
     * covers no elements.
     
     若是分割迭代器不包含任何元素。 其餘的屬性對客戶端是沒有任何幫助的。 然而會促進分割迭代器共享的做用。
     
     * @return a {@code Spliterator} over the elements in this collection
     * @since 1.8
     */
    @Override
    default Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, 0);
    }

Spliterator javadoc

/**
 * An object for traversing and partitioning elements of a source.  The source
 * of elements covered by a Spliterator could be, for example, an array, a
 * {@link Collection}, an IO channel, or a generator function.

 * <p>A Spliterator may traverse elements individually ({@link
 * #tryAdvance tryAdvance()}) or sequentially in bulk
 * ({@link #forEachRemaining forEachRemaining()}).   
一個一個去遍歷 tryAdvance() 或者  成塊的遍歷forEachRemaining()
 *
 * <p>A Spliterator may also partition off some of its elements (using
 * {@link #trySplit}) as another Spliterator, to be used in
 * possibly-parallel operations.  Operations using a Spliterator that
 * cannot split, or does so in a highly imbalanced or inefficient
 * manner, are unlikely to benefit from parallelism.  Traversal
 * and splitting exhaust elements; each Spliterator is useful for only a single
 * bulk computation.
 
 Spliterator 能夠對元素進行分區。 分紅新的Spliterator。 而且以並行的操做來實行。    
 若是不能分割這些操做,則不能經過並行操做受益。
 遍歷和分割都會對那一小塊是有用的、

 * <p>A Spliterator also reports a set of {@link #characteristics()} of its
 * structure, source, and elements from among {@link #ORDERED},
 * {@link #DISTINCT}, {@link #SORTED}, {@link #SIZED}, {@link #NONNULL},
 * {@link #IMMUTABLE}, {@link #CONCURRENT}, and {@link #SUBSIZED}. These may
 * be employed by Spliterator clients to control, specialize or simplify
 * computation.  For example, a Spliterator for a {@link Collection} would
 * report {@code SIZED}, a Spliterator for a {@link Set} would report
 * {@code DISTINCT}, and a Spliterator for a {@link SortedSet} would also
 * report {@code SORTED}.  Characteristics are reported as a simple unioned bit
 * set.

    特性值:ORDERED 有序的, DISTINCT 不一樣的,SORTED 帶排序的,SIZED 肯定大小的, 
            NONNULL 非空的, IMMUTABLE,  CONCURRENT  ,SUBSIZED 
    這些特性能夠在客戶端使用,用來簡化計算。是以位操做的形式來表示的。 collector中是以枚舉形式來表示的。

 * Some characteristics additionally constrain method behavior; for example if
 * {@code ORDERED}, traversal methods must conform to their documented ordering.
 * New characteristics may be defined in the future, so implementors should not
 * assign meanings to unlisted values.
 
    將來可能會定義一下新的特性。 實現者不該該賦予新的含義。

 * <p><a name="binding">A Spliterator that does not report {@code IMMUTABLE} or
 * {@code CONCURRENT} is expected to have a documented policy concerning:
 * when the spliterator <em>binds</em> to the element source; and detection of
 * structural interference of the element source detected after binding.</a>  A
 * <em>late-binding</em> Spliterator binds to the source of elements at the
 * point of first traversal, first split, or first query for estimated size,
 * rather than at the time the Spliterator is created.  A Spliterator that is
 * not <em>late-binding</em> binds to the source of elements at the point of
 * construction or first invocation of any method.  Modifications made to the
 * source prior to binding are reflected when the Spliterator is traversed.
 * After binding a Spliterator should, on a best-effort basis, throw
 * {@link ConcurrentModificationException} if structural interference is
 * detected.  Spliterators that do this are called <em>fail-fast</em>.  The
 * bulk traversal method ({@link #forEachRemaining forEachRemaining()}) of a
 * Spliterator may optimize traversal and check for structural interference
 * after all elements have been traversed, rather than checking per-element and
 * failing immediately.

  當Spliterator 綁定到源上時 , 要考慮   IMMUTABLE 和 CONCURRENT 。
  延遲迭代器會在第一次遍歷或者分割或者查詢大小的時候綁定在源上邊。而不是在建立的時候就被綁定在源上了。
  非延遲迭代器是在建立的時候就被綁定在源上了。
  在迭代器綁定後對源進行了修改。迭代器就能反應出來拋出異常ConcurrentModificationException。
  forEachRemaining()會優化遍歷,是在全部元素都被操做以後進行操做,而不是一個元素一個元素的檢測、

 * <p>Spliterators can provide an estimate of the number of remaining elements
 * via the {@link #estimateSize} method.  Ideally, as reflected in characteristic
 * {@link #SIZED}, this value corresponds exactly to the number of elements
 * that would be encountered in a successful traversal.  However, even when not
 * exactly known, an estimated value value may still be useful to operations
 * being performed on the source, such as helping to determine whether it is
 * preferable to split further or traverse the remaining elements sequentially.
 
    若是 特性值 SIZED 。 那麼將要遍歷的數量是肯定的。
    若是不包含SIZED,一個估算的值對於源的操做也是有幫助的。
 
 * <p>Despite their obvious utility in parallel algorithms, spliterators are not
 * expected to be thread-safe; instead, implementations of parallel algorithms
 * using spliterators should ensure that the spliterator is only used by one
 * thread at a time.  This is generally easy to attain via <em>serial
 * thread-confinement</em>, which often is a natural consequence of typical
 * parallel algorithms that work by recursive decomposition.  A thread calling
 * {@link #trySplit()} may hand over the returned Spliterator to another thread,
 * which in turn may traverse or further split that Spliterator.  The behaviour
 * of splitting and traversal is undefined if two or more threads operate
 * concurrently on the same spliterator.  If the original thread hands a
 * spliterator off to another thread for processing, it is best if that handoff
 * occurs before any elements are consumed with {@link #tryAdvance(Consumer)
 * tryAdvance()}, as certain guarantees (such as the accuracy of
 * {@link #estimateSize()} for {@code SIZED} spliterators) are only valid before
 * traversal has begun.
 
 分割迭代器並不確保是線程安全的。相反 應該確保分割迭代器一次被一個線程操做、
  能夠經過遞歸的方式來實現。
    
 * <p>Primitive subtype specializations of {@code Spliterator} are provided for
 * {@link OfInt int}, {@link OfLong long}, and {@link OfDouble double} values.
 * The subtype default implementations of
 * {@link Spliterator#tryAdvance(java.util.function.Consumer)}
 * and {@link Spliterator#forEachRemaining(java.util.function.Consumer)} box
 * primitive values to instances of their corresponding wrapper class.  Such
 * boxing may undermine any performance advantages gained by using the primitive
 * specializations.  To avoid boxing, the corresponding primitive-based methods
 * should be used.  For example,
 * {@link Spliterator.OfInt#tryAdvance(java.util.function.IntConsumer)}
 * and {@link Spliterator.OfInt#forEachRemaining(java.util.function.IntConsumer)}
 * should be used in preference to
 * {@link Spliterator.OfInt#tryAdvance(java.util.function.Consumer)} and
 * {@link Spliterator.OfInt#forEachRemaining(java.util.function.Consumer)}.
 * Traversal of primitive values using boxing-based methods
 * {@link #tryAdvance tryAdvance()} and
 * {@link #forEachRemaining(java.util.function.Consumer) forEachRemaining()}
 * does not affect the order in which the values, transformed to boxed values,
 * are encountered.
 
 爲了不重複的裝箱和拆箱,咱們應該使用巨化的方法。 減小使用通用的方法。
 *
 * @apiNote
 * <p>Spliterators, like {@code Iterator}s, are for traversing the elements of
 * a source.  The {@code Spliterator} API was designed to support efficient
 * parallel traversal in addition to sequential traversal, by supporting
 * decomposition as well as single-element iteration.  In addition, the
 * protocol for accessing elements via a Spliterator is designed to impose
 * smaller per-element overhead than {@code Iterator}, and to avoid the inherent
 * race involved in having separate methods for {@code hasNext()} and
 * {@code next()}.
 
 分割迭代器 就像迭代器同樣。 用來遍歷源當中的元素的。
 Spliterator也支持並行的操做。方式是經過解耦,分解,單元素的遍歷迭代。
 Spliterator相比於Iterator來講,成本更低。tryAdvance()本質上也避免了hasNext()和next() 的資源上的競爭。
 
 * <p>For mutable sources, arbitrary and non-deterministic behavior may occur if
 * the source is structurally interfered with (elements added, replaced, or
 * removed) between the time that the Spliterator binds to its data source and
 * the end of traversal.  For example, such interference will produce arbitrary,
 * non-deterministic results when using the {@code java.util.stream} framework.

	對於可變源來講,可能會出現問題
	
 * <p>Structural interference of a source can be managed in the following ways
 * (in approximate order of decreasing desirability):
 * <ul>
 * <li>The source cannot be structurally interfered with.
 * <br>For example, an instance of
 * {@link java.util.concurrent.CopyOnWriteArrayList} is an immutable source.
 * A Spliterator created from the source reports a characteristic of
 * {@code IMMUTABLE}.</li>
 
 	CopyOnWriteArrayList 適合於 讀多寫少的場景。 他是一個不可變的源。會返回一個特性值IMMUTABLE
 
 * <li>The source manages concurrent modifications.
 * <br>For example, a key set of a {@link java.util.concurrent.ConcurrentHashMap}
 * is a concurrent source.  A Spliterator created from the source reports a
 * characteristic of {@code CONCURRENT}.</li>
 
  建立併發源、 特性值  CONCURRENT
  
 * <li>The mutable source provides a late-binding and fail-fast Spliterator.
 * <br>Late binding narrows the window during which interference can affect
 * the calculation; fail-fast detects, on a best-effort basis, that structural
 * interference has occurred after traversal has commenced and throws
 * {@link ConcurrentModificationException}.  For example, {@link ArrayList},
 * and many other non-concurrent {@code Collection} classes in the JDK, provide
 * a late-binding, fail-fast spliterator.</li>
 * <li>The mutable source provides a non-late-binding but fail-fast Spliterator.
 * <br>The source increases the likelihood of throwing
 * {@code ConcurrentModificationException} since the window of potential
 * interference is larger.</li>
 * <li>The mutable source provides a late-binding and non-fail-fast Spliterator.
 * <br>The source risks arbitrary, non-deterministic behavior after traversal
 * has commenced since interference is not detected.
 * </li>
 * <li>The mutable source provides a non-late-binding and non-fail-fast
 * Spliterator.
 * <br>The source increases the risk of arbitrary, non-deterministic behavior
 * since non-detected interference may occur after construction.
 * </li>
 * </ul>
 *
 // 串行的例子:
 * <p><b>Example.</b> Here is a class (not a very useful one, except
 * for illustration) that maintains an array in which the actual data
 * are held in even locations, and unrelated tag data are held in odd
 * locations. Its Spliterator ignores the tags.
 *	
 * <pre> {@code
 * class TaggedArray<T> {
 *   private final Object[] elements; // immutable after construction
 *   TaggedArray(T[] data, Object[] tags) {
 *     int size = data.length;
 *     if (tags.length != size) throw new IllegalArgumentException();
 *     this.elements = new Object[2 * size];
 *     for (int i = 0, j = 0; i < size; ++i) {
 *       elements[j++] = data[i];
 *       elements[j++] = tags[i];
 *     }
 *   }
 *
 *   public Spliterator<T> spliterator() {
 *     return new TaggedArraySpliterator<>(elements, 0, elements.length);
 *   }
 *
 *   static class TaggedArraySpliterator<T> implements Spliterator<T> {
 *     private final Object[] array;
 *     private int origin; // current index, advanced on split or traversal
 *     private final int fence; // one past the greatest index
 *
 *     TaggedArraySpliterator(Object[] array, int origin, int fence) {
 *       this.array = array; this.origin = origin; this.fence = fence;
 *     }
 *
 *     public void forEachRemaining(Consumer<? super T> action) {
 *       for (; origin < fence; origin += 2)
 *         action.accept((T) array[origin]);
 *     }
 *
 		// 讓這個迭代器往前走
 *     public boolean tryAdvance(Consumer<? super T> action) {
 *       if (origin < fence) {
 *         action.accept((T) array[origin]);
 *         origin += 2;
 *         return true;
 *       }
 *       else // cannot advance
 *         return false;
 *     }
 *
 		// 嘗試進行分割, 儘可能均勻的分割成兩半. 不成功返回null
 *     public Spliterator<T> trySplit() {
 *       int lo = origin; // divide range in half
 *       int mid = ((lo + fence) >>> 1) & ~1; // force midpoint to be even
 *       if (lo < mid) { // split out left half
 *         origin = mid; // reset this Spliterator's origin
 *         return new TaggedArraySpliterator<>(array, lo, mid);
 *       }
 *       else       // too small to split
 *         return null;
 *     }
 *
 *     public long estimateSize() {
 *       return (long)((fence - origin) / 2);
 *     }
 *
 *     public int characteristics() {
 *       return ORDERED | SIZED | IMMUTABLE | SUBSIZED;
 *     }
 *   }
 * }}</pre>
 *
 // 並行的例子
 * <p>As an example how a parallel computation framework, such as the
 * {@code java.util.stream} package, would use Spliterator in a parallel
 * computation, here is one way to implement an associated parallel forEach,
 * that illustrates the primary usage idiom of splitting off subtasks until
 * the estimated amount of work is small enough to perform
 * sequentially. Here we assume that the order of processing across
 * subtasks doesn't matter; different (forked) tasks may further split
 * and process elements concurrently in undetermined order.  This
 * example uses a {@link java.util.concurrent.CountedCompleter};
 * similar usages apply to other parallel task constructions.
 *
 * <pre>{@code
 * static <T> void parEach(TaggedArray<T> a, Consumer<T> action) {
 *   Spliterator<T> s = a.spliterator();
 *   long targetBatchSize = s.estimateSize() / (ForkJoinPool.getCommonPoolParallelism() * 8);
 *   new ParEach(null, s, action, targetBatchSize).invoke();
 * }
 *
 * static class ParEach<T> extends CountedCompleter<Void> {
 *   final Spliterator<T> spliterator;
 *   final Consumer<T> action;
 *   final long targetBatchSize;
 *
 *   ParEach(ParEach<T> parent, Spliterator<T> spliterator,
 *           Consumer<T> action, long targetBatchSize) {
 *     super(parent);
 *     this.spliterator = spliterator; this.action = action;
 *     this.targetBatchSize = targetBatchSize;
 *   }
 *
 *   public void compute() {
 *     Spliterator<T> sub;
 *     while (spliterator.estimateSize() > targetBatchSize &&
 *            (sub = spliterator.trySplit()) != null) {
 *       addToPendingCount(1);
 *       new ParEach<>(this, sub, action, targetBatchSize).fork();
 *     }
 *     spliterator.forEachRemaining(action);
 *     propagateCompletion();
 *   }
 * }}</pre>
 *
 * @implNote
 * If the boolean system property {@code org.openjdk.java.util.stream.tripwire}
 * is set to {@code true} then diagnostic warnings are reported if boxing of
 * primitive values occur when operating on primitive subtype specializations.
 *   若是 {@code org.openjdk.java.util.stream.tripwire} 被設置成true, 則會給出警告。
 * @param <T> the type of elements returned by this Spliterator
 *
 * @see Collection
 * @since 1.8
 */
public interface Spliterator<T> {
      // 。。。  下方列舉幾個
}

tryAdvance();

/**
 * If a remaining element exists, performs the given action on it,
 * returning {@code true}; else returns {@code false}.  If this
 * Spliterator is {@link #ORDERED} the action is performed on the
 * next element in encounter order.  Exceptions thrown by the
 * action are relayed to the caller.
 *
 * @param action The action
 * @return {@code false} if no remaining elements existed
 * upon entry to this method, else {@code true}.
 * @throws NullPointerException if the specified action is null
 */
//嘗試的去前進。若是有下一個元素,則進行動做。
boolean tryAdvance(Consumer<? super T> action);

forEachRemaining();

/**
 * Performs the given action for each remaining element, sequentially in
 * the current thread, until all elements have been processed or the action
 * throws an exception.  If this Spliterator is {@link #ORDERED}, actions
 * are performed in encounter order.  Exceptions thrown by the action
 * are relayed to the caller.
 *
 * @implSpec
 * The default implementation repeatedly invokes {@link #tryAdvance} until
 * it returns {@code false}.  It should be overridden whenever possible.
 *
 * @param action The action
 * @throws NullPointerException if the specified action is null
 */
// 針對於剩餘的元素進行操做。
default void forEachRemaining(Consumer<? super T> action) {
    do { } while (tryAdvance(action));
}

trySplit();

/**
 * If this spliterator can be partitioned, returns a Spliterator
 * covering elements, that will, upon return from this method, not
 * be covered by this Spliterator.
 * 若是這個分割迭代器能被分割,則返回一個新的被分割出來的Spliterator對象。
 不會影響當前的spliterator
 * <p>If this Spliterator is {@link #ORDERED}, the returned Spliterator
 * must cover a strict prefix of the elements.
 *若是Spliterator是有序的,則返回的也應該是有序的Spliterator
 * <p>Unless this Spliterator covers an infinite number of elements,
 * repeated calls to {@code trySplit()} must eventually return {@code null}.
  除非Spliterator 返回的是無窮的元素,其他的最終返回一個null . 表示不能再繼續分割了。
 * Upon non-null return:
 若是返回不爲Null的話, 
 * <ul>
 * <li>the value reported for {@code estimateSize()} before splitting,
 * must, after splitting, be greater than or equal to {@code estimateSize()}
 * for this and the returned Spliterator; and</li>
 分割前的estimateSize>= 返回的estimateSize
 * <li>if this Spliterator is {@code SUBSIZED}, then {@code estimateSize()}
 * for this spliterator before splitting must be equal to the sum of
 * {@code estimateSize()} for this and the returned Spliterator after
 * splitting.</li>
 若是大小是固定的。則分割後的 estimateSize 的總和 等於分割前的 estimateSize
 * </ul>
 *
 * <p>This method may return {@code null} for any reason,
 * including emptiness, inability to split after traversal has
 * commenced, data structure constraints, and efficiency
 * considerations.
 * 
 * @apiNote
 * An ideal {@code trySplit} method efficiently (without
 * traversal) divides its elements exactly in half, allowing
 * balanced parallel computation.  Many departures from this ideal
 * remain highly effective; for example, only approximately
 * splitting an approximately balanced tree, or for a tree in
 * which leaf nodes may contain either one or two elements,
 * failing to further split these nodes.  However, large
 * deviations in balance and/or overly inefficient {@code
 * trySplit} mechanics typically result in poor parallel
 * performance.
 *理想狀況下,是從中間分割的,容許並行計算。不少狀況下不知足這種的、
 然而沒有效率的分割,會下降效率
 * @return a {@code Spliterator} covering some portion of the
 * elements, or {@code null} if this spliterator cannot be split
 */
//嘗試分割。
Spliterator<T> trySplit();

estimateSize();

/**
 * Returns an estimate of the number of elements that would be
 * encountered by a {@link #forEachRemaining} traversal, or returns {@link
 * Long#MAX_VALUE} if infinite, unknown, or too expensive to compute.
 *
 * <p>If this Spliterator is {@link #SIZED} and has not yet been partially
 * traversed or split, or this Spliterator is {@link #SUBSIZED} and has
 * not yet been partially traversed, this estimate must be an accurate
 * count of elements that would be encountered by a complete traversal.
 * Otherwise, this estimate may be arbitrarily inaccurate, but must decrease
 * as specified across invocations of {@link #trySplit}.
 * 分的越少,estimateSize要比原來的個數要小。
 * @apiNote
 * Even an inexact estimate is often useful and inexpensive to compute.
 * For example, a sub-spliterator of an approximately balanced binary tree
 * may return a value that estimates the number of elements to be half of
 * that of its parent; if the root Spliterator does not maintain an
 * accurate count, it could estimate size to be the power of two
 * corresponding to its maximum depth.
 *一個不精算的數量也是有用的。   
 * @return the estimated size, or {@code Long.MAX_VALUE} if infinite,
 *         unknown, or too expensive to compute.
 */
//估算大小
long estimateSize();

characteristics();

/**
 * Returns a set of characteristics of this Spliterator and its
 * elements. The result is represented as ORed values from {@link
 * #ORDERED}, {@link #DISTINCT}, {@link #SORTED}, {@link #SIZED},
 * {@link #NONNULL}, {@link #IMMUTABLE}, {@link #CONCURRENT},
 * {@link #SUBSIZED}.  Repeated calls to {@code characteristics()} on
 * a given spliterator, prior to or in-between calls to {@code trySplit},
 * should always return the same result.
 
 一個特性值的集合。
 重複的調用characteristics  在spliterator以前或者當中,會返回相同的結果。
 
 * <p>If a Spliterator reports an inconsistent set of
 * characteristics (either those returned from a single invocation
 * or across multiple invocations), no guarantees can be made
 * about any computation using this Spliterator.
 
  若是返回了一個不一致的特性值的集合。結果是不被保障的。
 
 * @apiNote The characteristics of a given spliterator before splitting
 * may differ from the characteristics after splitting.  For specific
 * examples see the characteristic values {@link #SIZED}, {@link #SUBSIZED}
 * and {@link #CONCURRENT}.
 *
 * @return a representation of characteristics
 */
//特性值。
int characteristics();

hasCharacteristics();

/**
 * Returns {@code true} if this Spliterator's {@link
 * #characteristics} contain all of the given characteristics.
 *
 * @implSpec
 * The default implementation returns true if the corresponding bits
 * of the given characteristics are set.
 * 默認的話,包含 會返回true
 * @param characteristics the characteristics to check for
 * @return {@code true} if all the specified characteristics are present,
 * else {@code false}
 */
// 判斷是否包含給定的特性值。  
default boolean hasCharacteristics(int characteristics) {
    return (characteristics() & characteristics) == characteristics;
}

getComparator();

/**
 * If this Spliterator's source is {@link #SORTED} by a {@link Comparator},
 * returns that {@code Comparator}. If the source is {@code SORTED} in
 * {@linkplain Comparable natural order}, returns {@code null}.  Otherwise,
 * if the source is not {@code SORTED}, throws {@link IllegalStateException}.
 *
 * @implSpec
 * The default implementation always throws {@link IllegalStateException}.
 *
 * @return a Comparator, or {@code null} if the elements are sorted in the
 * natural order.
 * @throws IllegalStateException if the spliterator does not report
 *         a characteristic of {@code SORTED}.
 */
//有序的話 返回一個Null。 其餘狀況 拋異常
default Comparator<? super T> getComparator() {
    throw new IllegalStateException();
}

IMMUTABLE

/**
 * Characteristic value signifying that the element source cannot be
 * structurally modified; that is, elements cannot be added, replaced, or
 * removed, so such changes cannot occur during traversal. A Spliterator
 * that does not report {@code IMMUTABLE} or {@code CONCURRENT} is expected
 * to have a documented policy (for example throwing
 * {@link ConcurrentModificationException}) concerning structural
 * interference detected during traversal.
 */
public static final int IMMUTABLE  = 0x00000400;   // 不能被修改的

CONCURRENT

/**
 * Characteristic value signifying that the element source may be safely
 * concurrently modified (allowing additions, replacements, and/or removals)
 * by multiple threads without external synchronization. If so, the
 * Spliterator is expected to have a documented policy concerning the impact
 * of modifications during traversal.
 *
 * <p>A top-level Spliterator should not report both {@code CONCURRENT} and
 * {@code SIZED}, since the finite size, if known, may change if the source
 * is concurrently modified during traversal. Such a Spliterator is
 * inconsistent and no guarantees can be made about any computation using
 * that Spliterator. Sub-spliterators may report {@code SIZED} if the
 * sub-split size is known and additions or removals to the source are not
 * reflected when traversing.
 *
 * @apiNote Most concurrent collections maintain a consistency policy
 * guaranteeing accuracy with respect to elements present at the point of
 * Spliterator construction, but possibly not reflecting subsequent
 * additions or removals.
 */
public static final int CONCURRENT = 0x00001000;

OfPrimitive

/**
 * A Spliterator specialized for primitive values.
 *
 * @param <T> the type of elements returned by this Spliterator.  The
 * type must be a wrapper type for a primitive type, such as {@code Integer}
 * for the primitive {@code int} type.
 * @param <T_CONS> the type of primitive consumer.  The type must be a
 * primitive specialization of {@link java.util.function.Consumer} for
 * {@code T}, such as {@link java.util.function.IntConsumer} for
 * {@code Integer}.
 * @param <T_SPLITR> the type of primitive Spliterator.  The type must be
 * a primitive specialization of Spliterator for {@code T}, such as
 * {@link Spliterator.OfInt} for {@code Integer}.
 *
 * @see Spliterator.OfInt
 * @see Spliterator.OfLong
 * @see Spliterator.OfDouble
 * @since 1.8
 */
public interface OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
        extends Spliterator<T> {
    @Override
    T_SPLITR trySplit();

    /**
     * If a remaining element exists, performs the given action on it,
     * returning {@code true}; else returns {@code false}.  If this
     * Spliterator is {@link #ORDERED} the action is performed on the
     * next element in encounter order.  Exceptions thrown by the
     * action are relayed to the caller.
     *
     * @param action The action
     * @return {@code false} if no remaining elements existed
     * upon entry to this method, else {@code true}.
     * @throws NullPointerException if the specified action is null
     */
    @SuppressWarnings("overloads")
    boolean tryAdvance(T_CONS action);

    /**
     * Performs the given action for each remaining element, sequentially in
     * the current thread, until all elements have been processed or the
     * action throws an exception.  If this Spliterator is {@link #ORDERED},
     * actions are performed in encounter order.  Exceptions thrown by the
     * action are relayed to the caller.
     *
     * @implSpec
     * The default implementation repeatedly invokes {@link #tryAdvance}
     * until it returns {@code false}.  It should be overridden whenever
     * possible.
     *
     * @param action The action
     * @throws NullPointerException if the specified action is null
     */
    @SuppressWarnings("overloads")
    default void forEachRemaining(T_CONS action) {
        do { } while (tryAdvance(action));
    }
}

OfInt

/**
 * A Spliterator specialized for {@code int} values.
 * @since 1.8
 */
public interface OfInt extends OfPrimitive<Integer, IntConsumer, OfInt> {

    @Override
    OfInt trySplit();

    @Override
    boolean tryAdvance(IntConsumer action);

    @Override
    default void forEachRemaining(IntConsumer action) {
        do { } while (tryAdvance(action));
    }

    /**
     * {@inheritDoc}
     * @implSpec
     * If the action is an instance of {@code IntConsumer} then it is cast
     * to {@code IntConsumer} and passed to
     * {@link #tryAdvance(java.util.function.IntConsumer)}; otherwise
     * the action is adapted to an instance of {@code IntConsumer}, by
     * boxing the argument of {@code IntConsumer}, and then passed to
     * {@link #tryAdvance(java.util.function.IntConsumer)}.
     */
    @Override
    default boolean tryAdvance(Consumer<? super Integer> action) {
        if (action instanceof IntConsumer) {
            return tryAdvance((IntConsumer) action);
        }
        else {
            if (Tripwire.ENABLED)
                Tripwire.trip(getClass(),
                              "{0} calling Spliterator.OfInt.tryAdvance((IntConsumer) action::accept)");
            return tryAdvance((IntConsumer) action::accept);
        }
    }

    /**
     * {@inheritDoc}
     * @implSpec
     * If the action is an instance of {@code IntConsumer} then it is cast
     * to {@code IntConsumer} and passed to
     * {@link #forEachRemaining(java.util.function.IntConsumer)}; otherwise
     * the action is adapted to an instance of {@code IntConsumer}, by
     * boxing the argument of {@code IntConsumer}, and then passed to
     * {@link #forEachRemaining(java.util.function.IntConsumer)}.
     */
    @Override
    default void forEachRemaining(Consumer<? super Integer> action) {
        if (action instanceof IntConsumer) {
            forEachRemaining((IntConsumer) action);
        }
        else {
            if (Tripwire.ENABLED)
                Tripwire.trip(getClass(),
                              "{0} calling Spliterator.OfInt.forEachRemaining((IntConsumer) action::accept)");
            forEachRemaining((IntConsumer) action::accept);
        }
    }
}

IntConsumer 和 Consumer 是沒有任何的關聯關係 的。可是爲何能(IntConsumer)Consumer

由於jdk自帶裝箱拆箱操做。 int 和 integer 重疊了。

Java8(7)流源結構代碼分析

流調用機制與原理大揭祕。

流執行操做時,先整理把中間的操做整合,當調用終止操做的時候,對每一個元素單個的進行全部的操做。操做中還帶有短路操做。

記錄下來,而後給別人再講,你就掌握了。

學完以後忘記了怎麼辦?記錄下來。 筆記 博客。 死記硬背是沒有任何用的。

ReferencePipeline

/**
 * Abstract base class for an intermediate pipeline stage or pipeline source
 * stage implementing whose elements are of type {@code U}.
 */
//引用管道   
//ReferencePipeline  表示流的源階段與中間階段。
//ReferencePipeline.head表示流中的源階段。
 abstract class ReferencePipeline<P_IN, P_OUT>
        extends AbstractPipeline<P_IN, P_OUT, Stream<P_OUT>>
        implements Stream<P_OUT>  {  
 }

AbstractPipeline

/**
 * Abstract base class for "pipeline" classes, which are the core
 * implementations of the Stream interface and its primitive specializations.
 * Manages construction and evaluation of stream pipelines.
 *	
 * <p>An {@code AbstractPipeline} represents an initial portion of a stream
 * pipeline, encapsulating a stream source and zero or more intermediate
 * operations.  The individual {@code AbstractPipeline} objects are often
 * referred to as <em>stages</em>, where each stage describes either the stream
 * source or an intermediate operation.
 流管道的初始的一部分。
 *
 * <p>A concrete intermediate stage is generally built from an
 * {@code AbstractPipeline}, a shape-specific pipeline class which extends it
 * (e.g., {@code IntPipeline}) which is also abstract, and an operation-specific
 * concrete class which extends that.  {@code AbstractPipeline} contains most of
 * the mechanics of evaluating the pipeline, and implements methods that will be
 * used by the operation; the shape-specific classes add helper methods for
 * dealing with collection of results into the appropriate shape-specific
 * containers.
 *避免自動拆箱和裝箱操做。
 * <p>After chaining a new intermediate operation, or executing a terminal
 * operation, the stream is considered to be consumed, and no more intermediate
 * or terminal operations are permitted on this stream instance.
 * 當連接完一個新的中間操做或者執行了終止操做以後, 這個流被認爲被消費了。不容許再被操做了。
 * @implNote
 * <p>For sequential streams, and parallel streams without
 * <a href="package-summary.html#StreamOps">stateful intermediate
 * operations</a>, parallel streams, pipeline evaluation is done in a single
 * pass that "jams" all the operations together.  For parallel streams with
 * stateful operations, execution is divided into segments, where each
 * stateful operations marks the end of a segment, and each segment is
 * evaluated separately and the result used as the input to the next
 * segment.  In all cases, the source data is not consumed until a terminal
 * operation begins.
  只有終止操做開始的時候,源數據纔會被消費。
 * @param <E_IN>  type of input elements
 * @param <E_OUT> type of output elements
 * @param <S> type of the subclass implementing {@code BaseStream}
 * @since 1.8
 */
abstract class AbstractPipeline<E_IN, E_OUT, S extends BaseStream<E_OUT, S>>
        extends PipelineHelper<E_OUT> implements BaseStream<E_OUT, S> {
}

內部類,和lambda表達式之間的關係。

本質上 內部類和lambda不是一回事。只是能完成相同的操做。

lambda不是匿名內部類的語法糖,或者說是縮寫。是一種新的形式。

public class LambdaTest {
    //內部類,和lambda表達式之間的關係。
    Runnable r1 = () -> System.out.println(this); // this表示當前類的對象

    //匿名內部類
    Runnable r2 = new Runnable() {  //
        @Override
        public void run() {
            System.out.println(this);
            // this 表示匿名內部類的對象
        }
    };


    public static void main(String[] args) {
        LambdaTest lambdaTest = new LambdaTest();

        Thread t1 = new Thread(lambdaTest.r1);
        t1.start();

        System.out.println("- - -- - ");

        Thread t2 = new Thread(lambdaTest.r2);
        t2.start();
        //輸出結果。
        //com.sinosoft.lis.test.LambdaTest@62661526
		//com.sinosoft.lis.test.LambdaTest$1@59a30351
    }

}

使用了模板方法模式。

流是惰性的,是延遲操做的。遇到終止操做時,纔會執行操做。

TerminalOp。 終止操做的接口類。

終止操做 只有四種類型, findOp foreachOp matchOp reduceOp

PipelineHelper

stream中間操做與終止操做層次體系分析與設計思想分析

中間操做

BaseStream -》 AbStractpipeline -》ReferencePipeline -》 Head || StatelessOP || statefulOp

最頂層的源 不少源的成員變量 管道 構造流源 無狀態的中間操做 有狀態的中間操做

流是惰性的,是延遲操做的。遇到終止操做時,纔會執行操做。再沒有終止操做以前,在整合中間操做(Sink)。

終止操做

TerminalOp -》 FindOp || ForeachOp || MatchOp || reduceOp

最頂層的

TerminalSink

終止的飲水槽。

Java8(8)時間日期API

joda-time

在開始學習jdk8.time以前,先接觸一下joda-time。

public static void main(String[] args) {
    // 基本使用方式.
    DateTime today = new DateTime();
    DateTime dateTime = today.plusDays(1);
    //今天
    System.out.println(today.toString("yyyy-MM-dd"));
    //明天
    System.out.println(dateTime.toString("yyyy-MM-dd"));
    System.out.println("- - - - -");
    //當月的第一天
    DateTime dateTime1 = today.withDayOfMonth(1);
    System.out.println(dateTime1.toString("yyyy-MM-dd"));
    // 當前時間後邊三個月的第後一天的日期
    LocalDate localDate = new LocalDate();
    localDate = localDate.plusMonths(3).dayOfMonth().withMaximumValue();
    System.out.println(localDate);
    // 當前時間後邊三個月的第一天的日期
    localDate = localDate.plusMonths(3).dayOfMonth().withMinimumValue();
    System.out.println(localDate);
    //計算兩年前的第三個月的最後一天的時期
    DateTime localDate1 = new DateTime();
    localDate1.minusYears(2).monthOfYear().setCopy(3).dayOfMonth().withMaximumValue();
    System.out.println(localDate1);
}
  • example:
public class JodaTest2 {
    // 標準UTC時間. 轉換成日期類型  2014-11-11T02:22:22.222z

    public static Date to2c(String date) {
        //服務器端轉換成客戶端的時間
        DateTime parse = DateTime.parse(date, DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ"));
        return parse.toDate();
    }

    public static String toString(Date date) {
//        客戶端的時間轉成服務器的時間
        DateTime date1 = new DateTime(date, DateTimeZone.UTC);
        return date1.toString();
    }

    public static String date2String(Date date,String dateFort) {
        DateTime dateTime = new DateTime(date);
        return dateTime.toString(dateFort);
    }

    public static void main(String[] args) {
        System.out.println(JodaTest2.to2c("2014-11-11T02:22:22.222z"));
        System.out.println(JodaTest2.toString(new Date()));  // 標準的時間爲 差8個小時
        System.out.println(JodaTest2.date2String(new Date(),"yyyy-MM-dd"));

    }
}

Java中日期時間的api

Java8中的全部時間都是不可變的,確保了線程安全。

沒有必要去研究源代碼。會用就能夠了。省下時間去學習更重要,更有價值的事情上。

{
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();
        System.out.println(localDate);
        //獲取年
        System.out.println(localDate.getYear());
        //獲取月
        System.out.println(localDate.getMonthValue());

        //根據年月日構造
        LocalDate localDate1 = LocalDate.of(2030, 3, 22);
        System.out.println(localDate1);

        //根據是時分秒構造
        LocalDate localDate2 = LocalDate.of(2020,3,25);
        MonthDay monthDay = MonthDay.of(localDate2.getMonth(), localDate2.getDayOfMonth());

        //根據是時分秒構造
        LocalTime localTime = LocalTime.now();
        System.out.println(localTime);

        // + 20分鐘, -2個小時
        LocalTime localTime1 = localTime.plusMinutes(20).minusHours(2);
        System.out.println(localTime1);

        System.out.println("- - - - -");

        //如今的時間增長兩週                                    (增長的長度,增長的單位)
        LocalDate localDate3 = LocalDate.now().plus(2, ChronoUnit.WEEKS);
        System.out.println(localDate3);

        //如今的時間減兩週
        LocalDate localDate4 = localDate.minus(2, ChronoUnit.MONTHS);
        System.out.println(localDate4);

        // Clock對象
        Clock clock = Clock.systemDefaultZone();
        System.out.println(clock);

        // 兩個日期進行的判斷
        LocalDate localDate5 = LocalDate.now();
        LocalDate localDate6 = LocalDate.of(2020,1,21);
        System.out.println(localDate5.isBefore(localDate6));
        System.out.println(localDate5.isAfter(localDate6));
        System.out.println(localDate5.equals(localDate6));

        //關於時區的概念.
        Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
        availableZoneIds.forEach(System.out::println);

        //將上邊的無序的時區set進行排序
        Set treeSet = new TreeSet<String>(){
            {addAll(availableZoneIds);}
        };
        treeSet.stream().forEach(System.out::println);

        //使用時區作一些例子.
        ZoneId zoneId = ZoneId.of("Asia/Shanghai");
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(localDateTime);

        ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId);
        System.out.println(zonedDateTime);

        System.out.println("- - -- - -");

         // 年月的對象
        YearMonth yearMonth = YearMonth.now();
        System.out.println(yearMonth);
        System.out.println(yearMonth.lengthOfMonth());
        System.out.println(yearMonth.isLeapYear());

        YearMonth yearMonth1 = YearMonth.of(2019, 2);
        System.out.println(yearMonth1);
        System.out.println(yearMonth1.lengthOfMonth());
        System.out.println(yearMonth1.lengthOfYear());
        System.out.println(yearMonth1.isLeapYear()); // 是否閏年

        LocalDate localDate7 = LocalDate.now();
        LocalDate localDate8 = LocalDate.of(2017, 3, 22);
        // Period 週期性的.. 比較兩個年份的差異
        Period period = Period.between(localDate7, localDate8); //
        System.out.println(period);
        System.out.println(period.getDays());

        System.out.println("- - -- - - ");
        // Instant  獲取不帶時區的UTC的標準時間.
        System.out.println(Instant.now());

        //,,,  剩下的用到的使用自行Google

    }
}

Java8(回顧總結)

Java8的回顧和覆盤

總共50節課,從開始到結束。學習到的不止是技術,更多的是學習方法。

系統的學習jdk8

  • Java 8新特性介紹
  • Lambda表達式介紹
  • 使用Lambda表達式代替匿名內部類
  • Lambda表達式的做用
  • 外部迭代與內部迭代
  • Java Lambda表達式語法詳解
  • 函數式接口詳解
  • 傳遞值與傳遞行爲
  • Stream深度解析
  • Stream API詳解
  • 串行流與並行流
  • Stream構成
  • Stream源生成方式
  • Stream操做類型
  • Stream轉換
  • Optional詳解
  • 默認方法詳解
  • 方法與構造方法引用
  • Predicate接口詳解
  • Function接口詳解
  • Consumer接口剖析
  • Filter介紹
  • Map-Reduce講解、中間操做與終止操做
  • 新的Date API分析

更多的時間是瞭解底層是怎麼實現的。

基礎的重要性

2020年02月07日12:03:41 將Java8學習的筆記給整理到了一個文件當中,方便整理。

原文出處:https://www.cnblogs.com/wobushitiegan/p/12315653.html

相關文章
相關標籤/搜索