Java8相關底層

Java8是往並行方向走的。由面向對象到函數式編程。java

在支持函數式編程的同時還能夠支持面向對象的開發。編程

在JDK1.8裏面,接口裏面能夠有實現方法的!默認方法,default。實現這個接口。數組

接口裏面能夠有靜態方法多線程

注意Lambda表達式的類型勢函數。可是在Java中,Lambda表達式是對象!他們必須依賴於一類特別的對象類型-函數式接口app

 

關於Function<T,R>接口框架

public class FunctionTest {
    public static void main(String[] args) {
        FunctionTest functionTest = new FunctionTest();
        //傳遞行爲
        System.out.println(functionTest.compute(1, value -> {return 10 * value;}));
    }

    public int compute (int a, Function<Integer, Integer> function){
        // 實現,由調用者去實現之
        int result = function.apply(a);
        return  result;
    }
}

解析:dom

 

 

單獨吧Lambda抽取出來:ide

public class FunctionTest {
    public static void main(String[] args) {
        //先把Lambda定義好
        Function<Integer, Integer> function = value -> value * 2;
        FunctionTest functionTest =  new FunctionTest();
        System.out.println(functionTest.compute(5, function));

    }

    public int compute(int a, Function<Integer, Integer> function){
        int result = function.apply(a);
        return result;
    }

}

 

  

 

多個function之間的串聯與前後關係的指定:函數式編程

public class FunctionTest {
    public static void main(String[] args) {
        FunctionTest functionTest = new FunctionTest();
        System.out.println(functionTest.compute1(2, value -> value * 3, value -> value *value));
        System.out.println(functionTest.compute2(2, value -> value * 3, value -> value *value));
    }

    public int compute1(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);
    }
}

 

compose源碼:函數

 

對比上面的例子,先執行function2 而後將結果賦值給function1去執行   

 

andThen是相反的。

 

因此,對於 R apply(T t);  要想實現兩個輸入一個輸出,是作不到的。能夠經過 BiFunction獲得。

public class FunctionTest {
    public static void main(String[] args) {
        FunctionTest functionTest = new FunctionTest();
        System.out.println(functionTest.compute4(2,3, (value1, value2) -> value1 + value2, value -> value * value));
    }

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

 

 

Predicate

 

 

filter的參數類型就是Predicate!

 

函數式編程提供了更高層次的抽象化:

 

 test() 名字都是抽象的,不具體。比較宏觀。

public class FunctionTest {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
        FunctionTest functionTest = new FunctionTest();
        functionTest.conditionFilter(list, item -> item % 2 == 0);
    }

   public void conditionFilter(List<Integer> list, Predicate<Integer> predicate){
        for (Integer integer : list){
           if (predicate.test(integer)){
               System.out.println(integer);
           }
        }
   }
} 

對於Predicate的default函數:

public class FunctionTest {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
        FunctionTest functionTest = new FunctionTest();
        functionTest.conditionFilter(list, item -> item % 2 == 0, item -> item < 6);
    }

    public void conditionFilter(List<Integer> list, Predicate<Integer> predicate1, Predicate<Integer> predicate2){
        for (Integer integer : list){
            // and 返回的是Predicate! 因此繼續 .test
            if (predicate1.and(predicate2).test(integer)){
//                if (predicate1.or(predicate2).test(integer)){
                if (predicate1.negate().test(integer)){  // 取反。知足條件後剩下的
            // 若是兩個都知足
                System.out.println(integer);
            }
        }
   }
}

 

靜態方法: 返回的也是Predicate 

 

做用就是判斷兩個參數是否相等。

public class FunctionTest {
    public static void main(String[] args) {
        FunctionTest functionTest = new FunctionTest();
        //isEqual傳進來的是test 而後和參數 「test」比較
        System.out.println(functionTest.isEqual(new Date()).test(new Date()));
    }
    public Predicate<Date> isEqual(Object object){
        return Predicate.isEqual(object);
    }
}

 

 

Comparator 仍是個函數式接口。裏面有好幾個函數式接口

結合BinaryOperator

 

Optional  是個容器,可能包含空值,非空值

 

public class FunctionTest {
    public static void main(String[] args) {
//        Optional<String> optional = Optional.empty();
        Optional<String> optional = Optional.of("valueTest");
        optional.ifPresent(item -> System.out.println(item));
        System.out.println(optional.orElse("world"));
        System.out.println(optional.orElseGet( () -> "hello"));
    }

}

 

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

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

        Employee employee2 = new Employee();
        employee2.setName("456");

        Company company = new Company();
        company.setName("c1");

        List<Employee> employees = Arrays.asList(employee1, employee2);

        company.setEmployees(employees);

        List<Employee> result = company.getEmployees();

//        if (result != null){
//            return result;
//        }else {
//            return new ArrayList<>();
//        }
        //一行代碼搞定
        Optional<Company> optional = Optional.ofNullable(company);
        System.out.println(optional.map( item -> item.getEmployees()).orElse(Collections.emptyList()));
    }

}

注意 Optional類型,不用作參數類型!  由於沒有序列化!

做爲返回類型,規避null! 

 

 

方法引用相似於函數指針。‘’

 

Remember:

           function 接收一個 返回一個   

           Supplier 只返回不接受

 

總結方法引用分4類:

   1. 類名::靜態方法名

   2. 引用名(對象名)::實例方法名

   3.  類名::實例方法名

   4. 構造方法引用:: 類名::new

 

流有個好處,支持並行化,對一個集合進行迭代,流能夠並行,多個線程進行處理。對於多核處理性能大大提高。

 

public class FunctionTest {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("a", "b", "c", "d");
        String[] strings = stream.toArray(length -> new String[length]);
        Arrays.asList(strings).forEach(System.out::println);
    }

}

改形成Lambda表達式構造函數引用:  經過構造函數引用的方式將數組傳遞進去

public class FunctionTest {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("a", "b", "c", "d");
        String[] strings = stream.toArray(String[]::new);
        Arrays.asList(strings).forEach(System.out::println);
    }

}

 

 


 

public class FunctionTest {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("a", "b", "c", "d");
        List<String> list1 = stream.collect(() -> new ArrayList(),
                (theList, item) -> theList.add(item),
                (theList1, theList2) -> theList1.addAll(theList2));

        //方法二
        List<String> list2 = stream.collect(LinkedList::new, LinkedList::add, LinkedList::addAll);
        list.stream().forEach(System.out::println);
    }

}

 

public class FunctionTest {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("a", "b", "c", "d");
        String str = stream.collect(Collectors.joining()).toString();
        System.out.println(str);
    }
}

 

flatMap去操做:

public class FunctionTest {
    public static void main(String[] args) {
        Stream<List<Integer>> listStream = Stream.of(Arrays.asList(1), Arrays.asList(2, 3), Arrays.asList(4, 5, 6));
        //每一個List轉成Stream
        listStream.flatMap( theList -> theList.stream())
                .map( item -> item * item).forEach(System.out::println);
    }
}

 

正確使用Optional:

public class FunctionTest {
    public static void main(String[] args) {
        Stream<String> stream = Stream.generate(UUID.randomUUID()::toString);
        //返回的是個Optional能夠調用get方法。 流裏面的第一個元素爲啥返回Optional。避免異常。若是流裏面沒有元素呢?規避之
        System.out.println(stream.findFirst().get());
        //若是存在元素的話...
        stream.findFirst().ifPresent(System.out::println);
        //能夠建立空的流
        Stream<String> stream1 = Stream.empty();
        stream1.findFirst().ifPresent(System.out::println);

    }
}

 

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

        Stream<Integer> stream = Stream.iterate(1, item -> item + 2).limit(6);
        IntSummaryStatistics summaryStatistics = stream.filter(item -> item > 2)
                .mapToInt(item -> item * 2).skip(2).limit(2).summaryStatistics();

        System.out.println( summaryStatistics.getMax());
        System.out.println( summaryStatistics.getMin());
    }
}

例子:Map: 中間操做,延遲操做。遇到終止操做時候纔會執行之

public class FunctionTest {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("hello", "world", "how are you");
        list.stream().map(
                item -> {
                    String result = item.substring(0, 1).toUpperCase() + item.substring(1);
                    System.out.println("----->");
                    return result;
                }
        ).forEach( System.out::println);
    }
}

 

Map和flatMap

 public static void main(String[] args) {

      List<String> list = Arrays.asList("hello welcome", "world hello");
//返回的List string類型的數組 四個數組對象不是不一樣的!
        List<String[]> result = list.stream()
// <R> Stream<R> map(Function<? super T, ? extends R> mapper);
.map(item -> item.split(" ")).distinct().collect(Collectors.toList());
result.forEach(
item -> Arrays.asList(item).forEach(System.out::println)
);
// flatMap System.out.println("----->flatMap"); List<String> resultFlatMap = list.stream().map(item -> item.split(" ")) //<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
          //將數組類型 轉成 String類型
.flatMap(Arrays::stream) // 接收的是一個數組類型。返回Stream類型。這樣返回四個Stream。 調用FlatMap把四個Stream合併成一個! .distinct().collect(Collectors.toList()); resultFlatMap.forEach(System.out::println); }

 

 

 

 

 

分析 FlatMap將結果打平了,結果放在一個流裏面。 

上述對於 FlatMap的使用, 首先map映射成字符串數組類型的內容, 而後將字符串數組打平。打平成一個Stream。即: 將 Stream<Strimg[]>  ------> Stream<String>

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

        List<String> list1 = Arrays.asList("你好", "哈哈");
        List<String> list2 = Arrays.asList("zhangsan", "lisi", "wangwu");

        List<String> result = list1.stream().flatMap(item -> list2.stream().map(item2 -> item + " " + item2)).collect(Collectors.toList());
        result.forEach(System.out::println);
    }
}

 

 

 

 Stream:

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

    當使用串行方式遍歷時,每特item讀完後再讀下一個

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

    Stream的並行操做依賴於Java7中引入的Fork/Join框架。任務分解成小任務。

    集合關注的是數據與數據存儲

    流關注的是數計算,流與迭代器相似的一點是: 流復發重複使用或者消費的。

   中間操做都會返回一個Stream對象,好比 Stream<Integer> Stream<Strimg>  好比 mapToInt返回 Stream<Integer>

   

 

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

        Employee employee1 = new Employee("a");
        Employee employee2 = new Employee("a");
        Employee employee3 = new Employee("b");
        Employee employee4 = new Employee("c");
        List<Employee> list = Arrays.asList(employee1, employee2, employee3, employee4);
        Map<String, Long> nameCountMap = list.stream().collect(Collectors.groupingBy(Employee::getName, Collectors.counting()));
        System.out.println(nameCountMap);

    }
}

 

 

 list.stream().collect(Collectors.groupingBy(Employee::getName, Collectors.averagingDouble(Employee::getScore));

 

 

分組:group by

分區: partition by 區別group by 只能分兩組 ,好比 true false。 90以上及格,如下不及格

 

collect是Stream提供的一個方法。Collector做爲Collect方法的參數。Collector接口很是重要,分析之:

Collector是一個接口,文檔解釋「它是一個可變的匯聚操做,將輸入元素累積到一個可變的結果容器中;它會在全部元素處理完畢以後,將累積結果轉換爲一個最終的表示(這是一個可選操做。支持串行並行兩種方式執行。 

注意: 並行不必定比串行塊,由於並行涉及到線程切換。好比cpu 2核的,生成四個線程。勢必四個線程去加強這兩個核心,會存在上下文切換。

Collectors自己提供了關於Collectors的常見匯聚實現,Collectors自己是一個工廠。

Collector是由四個元素組成的

combiner函數,有四個線程同時去執行,那麼就會生成四個部分結果。而後合併成一個。用在並行流的場景。 

爲了確保串行與並行操做的結果等價性,Collector函數須要知足兩個條件,identity(同一性)與associativity(結合性)。

 

public interface Collector<T,A,R>    T:集合或者流中的每一個元素類型, A可變容器類型, R:結果類型

  ·

 

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

        Employee employee1 = new Employee("a", 12);
        Employee employee2 = new Employee("a", 23);
        Employee employee3 = new Employee("b", 43);
        Employee employee4 = new Employee("c", 34);
        List<Employee> employees = Arrays.asList(employee1, employee2, employee3, employee4);

        String collect1 = employees.stream().map(Employee::getName).collect(Collectors.joining(","));

        //連續分組
        Map<Integer, Map<String, List<Employee>>> collect = employees.stream()
                .collect(Collectors.groupingBy(Employee::getScore, Collectors.groupingBy(Employee::getName)));
        
        //分區
        Map<Boolean, List<Employee>> collect2 = employees.stream().collect(Collectors.partitioningBy(e -> e.getScore() > 3));
        
        //連續分區
        Map<Boolean, Map<Boolean, List<Employee>>> collect3 = employees.stream().collect(Collectors.partitioningBy(e -> e.getScore() > 80, Collectors.partitioningBy(e -> e.getScore() > 5)));

        //綜合實戰
        Map<Boolean, Long> collect4 = employees.stream().collect(Collectors.partitioningBy(employee -> employee.getScore() > 90, Collectors.counting()));

        Map<String, Employee> collect5 = employees.stream().collect(Collectors.groupingBy(Employee::getName,
                // 收集而後XXX
                Collectors.collectingAndThen(Collectors.minBy(Comparator.comparingInt(Employee::getScore)),
                        Optional::get)));

    }
}

 

排序:

 Collector.sort() 本質上是調用 list.sort()

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

        List<String> list = Arrays.asList("helloWorld", "nihao", "java");
        Collections.sort(list, (item1, item2) -> {return (item1.length() - item2.length());});
        System.out.println(list);
        //當lambda無法推斷類型時候,指定下
        Collections.sort(list, Comparator.comparingInt((String item) -> item.length()).reversed());
        list.sort(Comparator.comparingInt(String::length).reversed());
        list.sort(Comparator.comparingInt((String item) -> item.length()).reversed());
        //不區分大小寫的排序,兩個排序規則. 先升序,而後XXX.兩個比較規則,第一個相同就調用第二個方法。
        Collections.sort(list, Comparator.comparingInt(String::length).thenComparing(String.CASE_INSENSITIVE_ORDER));
        Collections.sort(list, Comparator.comparingInt(String::length).thenComparing( (item1, item2) -> item1.toLowerCase().compareTo(item2.toLowerCase())));
        Collections.sort(list, Comparator.comparingInt(String::length).thenComparing(Comparator.comparing(String::toLowerCase)));
        //長度但願等的,才須要進行第二次比較。小寫進行比較,小寫逆序。
        Collections.sort(list, Comparator.comparingInt(String::length).thenComparing(Comparator.comparing(String::toLowerCase, Comparator.reverseOrder())));
        Collections.sort(list, Comparator.comparingInt(String::length).reversed().thenComparing(Comparator.comparing(String::toLowerCase, Comparator.reverseOrder())));
        //多級排序
        Collections.sort(list, Comparator.comparingInt(String::length).reversed()
                // 相同的(比較結果爲0的,繼續使用下面的方法)
                .thenComparing(Comparator.comparing(String::toLowerCase, Comparator.reverseOrder()))
                // 是否起做用,取決於前面的比較狀況結果
                .thenComparing(Comparator.reverseOrder()));
    }
}

 

定義實現本身的收集器:

/**
 * 1.實現接口時候,要定義好泛型
 * 2.
 */
public class MySetCollector<T> implements Collector<T, Set<T>, Set<T>> {

    /**
     * 提供一個空的容器,供accumulator 後續方法調用
     * @return
     */
    @Override
    public Supplier<Set<T>> supplier() {
        System.out.println("-----> supplier");
        return HashSet<T>::new;
    }

    /**
     * 累加器類型的,接收兩個參數不返回值
     * @return
     */
    @Override
    public BiConsumer<Set<T>, T> accumulator() {
        System.out.println("-----> accumulator");
        //經過方法引用的方式返回了一個 BiConsumer 對象
//        return Set<T>::add;
     return (set, item) -> set.add(item);
    }

    /**
     * 將並行流,多個線程所執行的結果合併起來
     * @return
     */
    @Override
    public BinaryOperator<Set<T>> combiner() {
        // 把一個部分結果,添加到另一個部分結果中
        System.out.println("------> combiner");
        return (set1, set2) -> {
            set1.addAll(set2);
            return set1;
        };
    }

    /**
     * 多線程狀況下,最後一步要執行的。返回最終的結果類型。返回結果容器給用戶。
     * @return
     */
    @Override
    public Function<Set<T>, Set<T>> finisher() {
     //   return t -> t;
        return Function.identity();
    }

    /**
     * 返回一個set集合,表示當前的收集器諸多獨特性。
     * @return
     */
    @Override
    public Set<Characteristics> characteristics() {
        System.out.println("----->characteristics");
        // 直接返回一個不可變的集合,參數爲指定的特性
        return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH, UNORDERED));
    }

    public static void main(String[] args) {
        List<String> list = Arrays.asList("hello", "world", "welcome", "hello");
        Set<String> collect = list.stream().collect(new MySetCollector<>());
        System.out.println(collect);
    }
}

 

 

 看下面例子:

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("accumulator invoked");
        return (set, item) -> {
            set.add(item);
        };
    }

    @Override
    public BinaryOperator<Set<T>> combiner() {
        System.out.println("combiner invoked");
        return (set1, set2) -> {
            set1.addAll(set2);
            return set1;
        };
    }

    @Override
    public Function<Set<T>, Map<T, T>> finisher() {
        System.out.println("finisher invoked");
        return set -> {
            Map<T,T> map = new HashMap<>();
            set.stream().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));
    }

    public static void main(String[] args) {
        List<String> list = Arrays.asList("hello", "world", "welcome", "a", "b", "c");
        Set<String> set = new HashSet<>();
        set.addAll(list);
        System.out.println("set"+ set);

        Map<String, String> collect = set.stream().collect(new MySetCollector2<>());
        System.out.println(collect);
    }
}

 

    

收集器:

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

  1.     經過ColletcorImpl來實現
  2.     經過reduceing方法來實現(reducing方法自己又是經過CollectorImpl來實現) 

 

關於toList()

 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);
    }
相關文章
相關標籤/搜索