目錄:java
1、簡介程序員
2、函數接口編程
3、Lambda表達式api
4、目標類型數組
5、流閉包
6、function包併發
7、對併發的影響app
正文函數式編程
1、簡介函數
一、java中lambda的由來
開發類庫的程序員使用java時,發現抽象級別還不夠,尤爲是面對大型數據集合時,java還欠缺高效的並行操做。爲了編寫這類處理批量數據的並行類庫,就須要在爲java增長lambda表達式。
再如,當咱們定義一個線程類時,能夠將該類實現Runnable接口(該接口只有一個方法run()),並實現run方法便可。但大多數狀況下咱們可能並不這麼作,由於該線程可能只會被使用一次,此時咱們通常會使用匿名內部類將線程的行爲進行內聯,代碼舉例以下:
可是匿名內部類存在缺陷:
等等,因爲上述缺陷,須要藉助函數式編程得以解決。
2、函數式接口
咱們對面向對象編程並不陌生,面向對象編程是對數據進行抽象,而函數式編程是對行爲進行抽象。現實世界中,數據和行爲是並存的。
那麼什麼是函數式編程呢?其核心思想是:在思考問題時,使用不可變值和函數,函數對一個值進行處理,映射成另外一個值。
函數式接口定義:把只有一個抽象方法的接口稱爲函數式接口,可用作lambda表達式的類型。java中的函數式接口如Runnable、Comparator、Callable等。
如何自定義一個函數式接口?其實咱們並須要額外的工做來聲明一個接口是函數式接口,編譯器會根據接口的結構自行判斷,固然並不是簡單對接口中的方法進行計數。另外,java api提供了@FunctionalInterface註解來顯示聲明一個接口爲函數式接口,加上該註解後,編譯器就會驗證該接口是否知足函數式接口的要求。
java8中增長了一個新的package:java.util.function,裏面包含了經常使用的函數式接口。
3、Lambda表達式
lambda表達式又被稱爲閉包或匿名方法。
下面對lambda進行一些簡單舉例:
因而可知,lambda表達式由參數列表、箭頭符號(->)和函數體組成,其中函數體既能夠是一個表達式,也能夠是一個語句塊。表達式函數體適用於小型lambda表達式,它省略了return關鍵字,使語法更簡潔。
在使用lambda表達式時,能夠顯示聲明參數的類型,如:(int x, int y) -> x + y,其實也能夠省略參數類型,讓編譯器本身去推導出來,如:(x, y) -> x + y。
4、目標類型
一、目標類型
編譯器負責推導lambda表達式的類型,它利用lambda表達式所在上下文所期待的類型進行推導,這個被期待的類型就是目標類型。lambda只能出如今目標類型爲函數接口的上下文中。
lambda表達式對目標類型也是有要求的,當下面全部條件都成立時,lambda表達式纔會賦給目標類型T。
二、目標類型的上下文包括:
三、詞法做用域
lambda引用的是值,而不是變量。在匿名內部類中引用它所在方法的變量時,該變量必須聲明爲final,雖然Java8中放寬了此限制,能夠引用非final變量,可是該變量在既成事實上必須是final的,即不能再匿名內部類中改變它所在方法的變量值,不然編譯器會報錯。既成事實上的final是指只能給該變量賦值一次,換句話說,Lambda引用的是值,而不是變量。舉例以下:
上面兩個例子中,只要在內部類或lambda表達式中修改其所在方法中的變量都會報錯。lambda表達式不支持修改外部變量的另外一個緣由是:咱們可使用更好的方式實現相同的效果:使用規約。java.util.function包中提供了各類規約,如sum、min、max等。
在內部類中定義和外部類中相同的變量時,其內部類中定義的變量會覆蓋外部類中定義的變量。而lambda表達式基於詞法做用域,在lambda函數體裏面不容許定義和外面相同的變量,若是定義則會報錯。舉例:
所以,能夠說:lambda表達式對值封閉,對變量開放。
5、流
一、概念
外部迭代:經過Iterator的方式進行迭代的過程稱爲外部迭代。
內部迭代:經過stream的方式進行迭代的過程稱爲內部迭代。
流 - Stream:是用函數式編程的方式在集合類上進行復雜操做的工具。java8中爲集合類和數組都提供了轉爲Stream的方法,由集合或數組生成的Stream不是一個新集合,而是建立新集合的配方。
惰性求值方法:只描述或刻畫Stream,最終不產生新集合的方法叫惰性求值方法,如Stream的filter方法。
及早求值方法:最終會生成新集合的方法叫及早求值方法,如Stream的count方法。
說明:判斷一個方法是惰性求值仍是及早求值很簡單:只需看它的返回值,若是返回值是Stream,那麼就是惰性求值方法,若是返回的是另外一個值或空,就是及早求值方法。使用這些操做的理想方式就是造成一個惰性求值的鏈,最後用一個及早求值的操做返回想要的結果。
二、經常使用的流操做
2.1 collect(Collector<? super T,A,R>)
做用:該方法由Stream裏的值生成一個列表,是一個及早求值方法。
舉例:
List<String> list = Stream.of("a", "1", "b", "2").collect(Collectors.toList());
2.2 Stream<R> map(Function<? super T, ? super R>)
做用:將一個流中的值轉換成一個新流,是一個惰性求值方法。
舉例:
Stream<String> stream = Stream.of("a","b","c").map(one -> one.toUpperCase());
2.3 Stream<T> filter(Predicate<? super T>)
做用:遍歷流中的數據並根據條件進行過濾,造成一個新流,是一個惰性求值方法。
舉例:
Stream<String> stream1 = Stream.of("abc","bcd","def").filter(one -> one.contains("bc"));
2.4 Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>>)
做用:當流中包含多個列表時,可將這多個列表中的內容打平放到一個列表下的流中,是一個惰性求值方法。
舉例:
Stream<String> stream2 = Stream.of(Arrays.asList("a","b","c"), Arrays.asList("abc","bcd","def")).flatMap(one -> one.stream());
2.5 Optional<T> max(Comparator<? super T>)和Optional<T> min(Comparator<? super T>)
做用:獲取一個集合中的最大值和最小值,是兩個及早求值方法
舉例:
Integer max = Stream.of(1,2,3).max(Comparator.comparing(one->one)).get();
Integer min = Stream.of(1,2,3).min(Comparator.comparing(one->one)).get();
2.6 long count()
做用:返回Stream中元素的數量,是一個及早求值方法
舉例:
Long count = Stream.of(1,2,3).count();
2.7 Optional<T> reduce(BinaryOperator<T>)
做用:從stream的一組值中生成1個值,count、max、min都屬於reduce操做,是一個及早求值方法。
舉例:第1個參數one是上次函數計算的返回值,其初始值是stream中第1個值;第2個參數two是stream中的元素值,其初始值是stream中第2個值,返回類型是Optional,經過get方法獲取其值
Integer count = Stream.of(1,2,3,4,5,6).reduce((one, two) -> { System.out.println(one + ":"+two);return two; }).get();
2.8 T reduce(T, BinaryOperator<T>)
舉例:該方法比上一個方法多了一個初始值100,one仍然表明上次函數計算的返回值,其初始值爲就是設定的初始值100;two仍然是stream中的元素值,其初始值是stream中的第1個值。因爲該方法指定了初始值,所以該方法的返回值類型就是設定的初始值類型,即Integer。
Integer count1 = Stream.of(1,2,3,4,5,6).reduce(100, (one, two) -> { System.out.println(one + ":"+two);return two; });
2.9 Stream<T> distinct()
做用:返回由該流的不一樣元素組成的一個新流,是一個惰性求值方法
舉例:
Stream.of(3,2,5,3,4,3).distinct().peek(one -> System.out.println(one)).count();
2.10 Stream<T> limit(int maxSize)
做用:返回前maxSize個元素組成的新流,是一個惰性求值方法
舉例:
System.out.println(Stream.of(1,2,3,4,5,6).limit(3).filter(one -> {System.out.println(one);return true;}).count());
2.11 Stream<T> peek(Consumer<? super T>)
做用:返回一個由該流的元素組成的新流,而且對新流中每一個元素執行指定的操做
舉例:
Stream stream = Stream.of(1,2,3,4,5,6).peek(one -> System.out.println(one));
2.12 Stream<T> skip(long n)
做用:從流的第1個元素開始,跳過n個元素,把從第n+1個元素開始到最後全部的元素造成一個新流
舉例:
Stream.of(1,2,3,4,5,6).skip(3).peek(one -> System.out.println(one)).count();
2.13 Stream<T> sorted()
做用:將流中的元素按照天然順序進行排序,是一個惰性求值方法
舉例:
Stream.of(6,2,5,3,4,1).peek(one-> System.out.println(one)).sorted().peek(one-> System.out.println(one)).count();
2.14 boolean allMatch(Predicate<? super T>)
做用:返回流中的全部元素是否都與條件匹配
舉例:
System.out.println(Stream.of(6,2,5,3,4,1).allMatch(one -> one>3));
2.15 boolean anyMatch(Predicate<? super T>)
做用:返回流中是否存在與條件匹配的元素
舉例:
System.out.println(Stream.of(6,2,5,3,4,1).anyMatch(one -> one>3));
2.16 boolean noneMatch(Predicate<? super T>)
做用:返回流中全部元素是否都不與條件匹配
舉例:
System.out.println(Stream.of(6,2,5,3,4,1).noneMatch(one -> one>3));
2.17 findAny()
做用:返回描述流的一些元素的Optional對象,若是流爲空,則返回一個空Optional
舉例:
System.out.println(Stream.of(3,2,5,6,4,1).findAny().get());
2.18 findFirst()
做用:返回描述流的第一個元素的Optional對象,若是流爲空,則返回一個空Optional
舉例:
System.out.println(Stream.of(3,2,5,6,4,1).findAny().get());
2.19 void forEach(Consumer<? super T>)
做用:對流中每一個元素循環進行操做
舉例:
Stream.of(3,2,5,6,4,1).forEach(one -> System.out.println(one));
2.20 Object[] toArray()
做用:返回一個包含流中元素的數組
舉例:
Integer[] values = (Integer[])Stream.of(3,2,5,6,4,1).toArray();
6、function包
一、Predicate<T>
抽象方法爲boolean test(T),傳入T類型的參數,返回一個boolean類型值。可用於流中數值判斷。
舉例:
Predicate<String> predicate = one -> one.length() > 0;
二、Consumer<T>
抽象方法爲void accept(T),傳入T類型的參數,不返回值。可用於實現消費者
舉例:
Consumer<Integer> consumer = one -> System.out.println(one);
三、Supplier<T>
抽象方法爲String[] value(),無參數,返回一個字符串數組。可用於實現生產者
舉例:
Supplier<Integer> supplier = () -> new Integer(100);
四、Function<T, R>
抽象方法爲R apply(T),傳入參數T,返回結果R。
舉例:
Function<String, Integer> function = one -> one.length();
五、UnaryOperator<T>
抽象方法T apply(T),接收T對象,返回T對象。
舉例:
UnaryOperator<String> unaryOperator = one -> "hello:" + one;
六、BinaryOperator<T>
抽象方法爲T apply(T, T),接收2個T對象,返回T對象。
舉例:
BinaryOperator<Integer> binaryOperator = (one, two) -> one + two;
7、對併發的影響
待續