Java函數式編程的第一個做用是能夠將匿名類改寫成函數式表達式,由系統自動判斷類型編程
咱們先定義一個接口app
public interface Goods { boolean test(int i); }
傳統的匿名類寫法ide
public class Anonymous { public static void main(String[] args) { List<Goods> goodsList = new ArrayList<>(); goodsList.add(new Goods(){ @Override public boolean test(int i) { return 5 - i > 0; } }); System.out.println(goodsList.get(0).test(3)); } }
運行結果:函數式編程
true函數
使用lamdba表示式的寫法工具
public class AnonymousLambda { public static void main(String[] args) { List<Goods> goodsList = new ArrayList<>(); goodsList.add(i -> 5 - i > 0); System.out.println(goodsList.get(0).test(3)); } }
運行結果ui
truethis
像這種一個接口裏面只有一個方法的接口,咱們能夠稱之爲函數接口,JDK中有不少這樣的接口,固然咱們能夠在該接口上打上@FunctionalInterface以代表該接口是一個函數接口spa
@FunctionalInterface public interface Goods { boolean test(int i); }
咱們先來看一下JDK中的Predicate接口,這是一個能夠進行條件判斷的接口code
咱們先用傳統方式來看一下這麼幾個條件
public class PredicateOne { /** * 判斷長度大於5 * @param judgeString * @return */ public boolean judgeStringLength(String judgeString) { return judgeString.length() > 5; } /** * 判斷是不是偶數 * @param judgeInteger * @return */ public boolean judgeIntegerOdds(int judgeInteger) { return (judgeInteger & 1) == 0; } /** * 判斷數字是否大於10 * @param num * @return */ public boolean judgeSecialNumber(int num) { return num > 10; } public static void main(String[] args) { PredicateOne predicateOne = new PredicateOne(); System.out.println(predicateOne.judgeStringLength("12345")); System.out.println(predicateOne.judgeIntegerOdds(12345)); System.out.println(predicateOne.judgeSecialNumber(12345)); } }
運行結果
false
false
true
如今改爲函數式編程以下
public class PredicateTwo<T> { public boolean judgeConditionByFunction(T t, Predicate<T> predicate) { return predicate.test(t); } public static void main(String[] args) { PredicateTwo<Integer> integerPredicateTwo = new PredicateTwo<>(); System.out.println(integerPredicateTwo.judgeConditionByFunction(12345,t -> String.valueOf(t).length() > 5)); System.out.println(integerPredicateTwo.judgeConditionByFunction(12345,t -> (t & 1) == 0)); System.out.println(integerPredicateTwo.judgeConditionByFunction(12345,t -> t > 10)); }
運行結果
false
false
true
咱們知道邏輯判斷中有與、或、非的比較,Predicate接口一樣具備這樣的功能,咱們來看一下它的源碼
@FunctionalInterface public interface Predicate<T> { /** * 須要實現的比較方法 * * @param t the input argument * @return {@code true} if the input argument matches the predicate, * otherwise {@code false} */ boolean test(T t); /** * 邏輯與,相似於&& * * @param other a predicate that will be logically-ANDed with this * predicate * @return a composed predicate that represents the short-circuiting logical * AND of this predicate and the {@code other} predicate * @throws NullPointerException if other is null */ default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } /** * 邏輯非,相似於! * * @return a predicate that represents the logical negation of this * predicate */ default Predicate<T> negate() { return (t) -> !test(t); } /** * 邏輯或,相似於|| * * @param other a predicate that will be logically-ORed with this * predicate * @return a composed predicate that represents the short-circuiting logical * OR of this predicate and the {@code other} predicate * @throws NullPointerException if other is null */ default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); } /** * 邏輯等,相似於equals()方法 * * @param <T> the type of arguments to the predicate * @param targetRef the object reference with which to compare for equality, * which may be {@code null} * @return a predicate that tests if two arguments are equal according * to {@link Objects#equals(Object, Object)} */ static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); } }
如今咱們加上條件的交集判斷
public class PredicateThree<T> { /** * 兩個條件的與操做 * @param t * @param predicate * @param predicate1 * @return */ public boolean judgeConditionByFunctionAnd(T t, Predicate<T> predicate,Predicate<T> predicate1) { return predicate.and(predicate1).test(t); } /** * 兩個條件的或操做 * @param t * @param predicate * @param predicate1 * @return */ public boolean judgeConditionByFunctionOr(T t, Predicate<T> predicate,Predicate<T> predicate1) { return predicate.or(predicate1).test(t); } /** * 對一個條件進行取反 * @param t * @param predicate * @return */ public boolean judgeConditionByFunctionNegate(T t,Predicate<T> predicate) { return predicate.negate().test(t); } /** * 判斷兩個對象的值是否相等 * @param t1 * @param t2 * @return */ public boolean judgeConditionIsEquals(T t1,T t2) { return Predicate.isEqual(t1).test(t2); } public static void main(String[] args) { PredicateThree<Integer> integerPredicateThree = new PredicateThree<>(); System.out.println(integerPredicateThree.judgeConditionByFunctionAnd(12345,t -> t > 10,t ->(t & 1) == 0)); System.out.println(integerPredicateThree.judgeConditionByFunctionOr(12345,t -> t > 10,t ->(t & 1) == 0)); System.out.println(integerPredicateThree.judgeConditionByFunctionNegate(12345,t -> t > 10)); System.out.println(integerPredicateThree.judgeConditionIsEquals(123,123)); } }
運行結果
false
true
false
true
咱們再來看一下JDK中的Consumer接口,Consumer的做用是 給定義一個參數,對其進行(消費)處理,處理的方式能夠是任意操做.
咱們來獲取一羣人中名字爲lisa的全部人,傳統方式以下
@Data @AllArgsConstructor public class Person { private String name; private int age; }
public class ConsumerOne { public static void main(String[] args) { List<Person> personList = new ArrayList<>(); Consumer<Person> consumer = new Consumer<Person>() { @Override public void accept(Person person) { if (person.getName().equals("lisa")) { personList.add(person); } } }; List<Person> list = Arrays.asList( new Person("lisa", 23), new Person("Mike", 33), new Person("lisa", 27), new Person("Jack", 25) ); for (Person person : list) { consumer.accept(person); } System.out.println(JSON.toJSONString(personList)); } }
運行結果
[{"age":23,"name":"lisa"},{"age":27,"name":"lisa"}]
改寫成函數式編程以下
public class ConsumerTwo { public static void main(String[] args) { List<Person> personList = new ArrayList<>(); Consumer<Person> consumer = t -> { if (t.getName().equals("lisa")) { personList.add(t); } }; Arrays.asList( new Person("lisa", 23), new Person("Mike", 33), new Person("lisa", 27), new Person("Jack", 25) ).stream().forEach(consumer); System.out.println(JSON.toJSONString(personList)); } }
運行結果
[{"age":23,"name":"lisa"},{"age":27,"name":"lisa"}]
stream後面會全面講解,咱們來看一下Consumer接口的源碼
@FunctionalInterface public interface Consumer<T> { /** * 給指定的參數t執行定義的操做 * * @param t the input argument */ void accept(T t); /** * 對給定的參數t執行定義的操做執行再繼續執行after定義的操做 * * @param after the operation to perform after this operation * @return a composed {@code Consumer} that performs in sequence this * operation followed by the {@code after} operation * @throws NullPointerException if {@code after} is null */ default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }
如今咱們只須要大於25歲的lisa
public class ConsumerThree { public static void main(String[] args) { List<Person> personList = new ArrayList<>(); Consumer<Person> consumer = t -> { if (t.getName().equals("lisa")) { personList.add(t); } }; consumer = consumer.andThen(t -> personList.removeIf(x -> x.getAge() < 25)); Arrays.asList( new Person("lisa", 23), new Person("Mike", 33), new Person("lisa", 27), new Person("Jack", 25) ).stream().forEach(consumer); System.out.println(JSON.toJSONString(personList)); } }
運行結果
[{"age":27,"name":"lisa"}]
這裏removeIf()的參數是一個Predicate接口,它的源碼以下,它是在Collection接口源碼中
default boolean removeIf(Predicate<? super E> filter) { Objects.requireNonNull(filter); boolean removed = false; final Iterator<E> each = iterator(); while (each.hasNext()) { if (filter.test(each.next())) { each.remove(); removed = true; } } return removed; }
咱們再來看一下JDK中的Function接口,Function的做用是將一個給定的對象進行加工,而後返回加工後的對象,這個加工能夠是任何操做.
傳統方式以下
@Data @AllArgsConstructor @ToString public class Person { private String name; private int age; }
@AllArgsConstructor @Data @ToString public class Result { private String msg; private String code; private Person person; }
public class FunctionOne { public static void main(String[] args) { Function<Person,Result> function = new Function<Person, Result>() { @Override public Result apply(Person person) { return new Result("成功","200",person); } }; System.out.println(function.apply(new Person("lisa",24))); } }
運行結果
Result(msg=成功, code=200, person=Person(name=lisa, age=24))
改寫成函數式編程以下
public class FunctionTwo { public static void main(String[] args) { Function<Person,Result> function = x -> new Result("成功","200",x); System.out.println(function.apply(new Person("lisa",24))); } }
運行結果
Result(msg=成功, code=200, person=Person(name=lisa, age=24))
Function接口的源碼以下
@FunctionalInterface public interface Function<T, R> { /** * 將一個給定的對象進行加工,而後返回加工後的對象,能夠將該方法理解爲一個一維函數,參數R是自變量,參數T是因變量. * * @param t the function argument * @return the function result */ R apply(T t); /** * 組合函數,在調用當前function以前執行 * * @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)); } /** * 組合函數,在調用當前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)); } /** * 原函數,返回與參數一致的函數,便可以理解爲 y = x * * @param <T> the type of the input and output objects to the function * @return a function that always returns its input argument */ static <T> Function<T, T> identity() { return t -> t; } }
----------------------------------------------------------------------------------
而另外一個最主要的做用就是對集合的操做,從傳統編程到函數式編程(lambda),咱們先來看一個最簡單的例子
@Data @AllArgsConstructor public class Artist { private String name; private String homeTown; public boolean isFrom(String homeTown) { if (this.homeTown.equals(homeTown)) { return true; } return false; } }
這是一個藝術家的簡單類,包含名字和家鄉。
如今咱們來建立一個藝術家的集合,而後斷定來自倫敦的藝術家有多少人
public class ComeFrom { public static void main(String[] args) { List<Artist> artists = new ArrayList<>(); artists.add(new Artist("Martin","London")); artists.add(new Artist("Shirly","Beijing")); artists.add(new Artist("Dilon","London")); artists.add(new Artist("Dave","NewYork")); int count = 0; for (Artist artist : artists) { if (artist.isFrom("London")) { count++; } } System.out.println(count); } }
運行結果:
2
如今咱們來改形成函數式的編程
public class ComeFromStream { public static void main(String[] args) { List<Artist> artists = new ArrayList<>(); artists.add(new Artist("Martin","London")); artists.add(new Artist("Shirly","Beijing")); artists.add(new Artist("Dilon","London")); artists.add(new Artist("Dave","NewYork")); long count = artists.stream().filter(artist -> artist.isFrom("London")) .count(); System.out.println(count); } }
運行結果
2
這裏第一種方式,咱們稱爲外部迭代;而第二種方式,咱們稱爲內部迭代,而stream是這種用函數式編程方式在集合類上進行復雜操做的工具。
若是咱們對代碼稍做修改
public class ComeFromStream { public static void main(String[] args) { List<Artist> artists = new ArrayList<>(); artists.add(new Artist("Martin","London")); artists.add(new Artist("Shirly","Beijing")); artists.add(new Artist("Dilon","London")); artists.add(new Artist("Dave","NewYork")); artists.stream().filter(artist -> { System.out.println(artist.getName()); return artist.isFrom("London"); }); } }
執行該端代碼,沒有任何輸出。像這種只過濾不計數的,filter只刻畫出了Stream,但並無產生新的集合的方法,咱們稱之爲惰性求值方法;而像count這樣最終會從Stream產生值的方法叫作及早求值方法。
咱們再把上述代碼改回求值。
public class ComeFromStream { public static void main(String[] args) { List<Artist> artists = new ArrayList<>(); artists.add(new Artist("Martin","London")); artists.add(new Artist("Shirly","Beijing")); artists.add(new Artist("Dilon","London")); artists.add(new Artist("Dave","NewYork")); long count = artists.stream().filter(artist -> { System.out.println(artist.getName()); return artist.isFrom("London"); }).count(); System.out.println(count); } }
運行結果
Martin
Shirly
Dilon
Dave
2
判斷一個操做是惰性求值仍是及早求值很簡單:只需看它的返回值。若是返回值是Stream,那麼是惰性求值;若是返回值是另外一個值或爲空,那麼就是及早求值。整個過程和建造者模式有共通之處。建造者模式使用一系列操做設置屬性和配置,最後調用build方法,這時,對象才被真正建立。