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驚天工廠類來講,其實現一共分爲兩種狀況:
關於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); }