看此文前,不熟悉函數式編程和Lambda表達式的能夠先看一下上文回憶一下。java
本文將會簡單介紹Java8中內置的一些函數式接口編程
函數式接口就是隻定義一個抽象方法的接口。在JAVA8之前,就有不少符合函數式接口定義的接口。segmentfault
//比較器 public interface Comparator<T> { int compare(T o1, T o2); } //多線程接口 public interface Runnable{ void run(); }
由於JAVA8中還引入了默認方法的概念,因此即便接口中有多個默認方法,只要接口之定義了一個抽象方法,就知足函數式接口的定義。數組
JAVA8中對這些能夠定義爲函數式接口的接口加了一個@FuncationalInterface
註解。若是一個接口中定義了多個抽象方法,又添加了這個註解,則會在編譯時拋出錯誤提示。多線程
package java.util.function; import java.util.Objects; @FunctionalInterface public interface Consumer<T> { void accept(T var1); default Consumer<T> andThen(Consumer<? super T> var1) { Objects.requireNonNull(var1); return (var2) -> { this.accept(var2); var1.accept(var2); }; } }
這是JAVA8中對Consumer的定義,該函數式接口能夠接收一個T類型的數據,並對該數據進行操做。JDK中一個典型的例子是forEach中對Consumer的使用,下面給出了ArrayList中的forEach源碼。app
@Override public void forEach(Consumer<? super E> consumer) { checkNotNull(consumer); for (E e : array) { consumer.accept(e); } }
forEach的接口定義中傳入了一個Consumer接口,而且調用Consumer的accept方法對數組中的每一個元素進行處理。加入這是一個String數組,則可使用以下的方式進行調用ide
list.forEach((String s) -> System.out::println);
在Consumer的接口定義中,還有一個andThen的默認方法,後面會再介紹一下這個默認方法。函數式編程
由於Consumer這個接口使用了泛型,所以只能使用基礎類型的封箱類型,如Integer,Long等。若是是對基礎類型的元素進行處理,可能會出現大量的封箱拆箱的操做,形成性能損耗。爲了解決這個問題,JAVA也提供了基礎類型的對應的Consumer接口,如IntConsumer:函數
@FunctionalInterface public interface IntConsumer { void accept(int value); default IntConsumer andThen(IntConsumer after) { Objects.requireNonNull(after); return (int t) -> { accept(t); after.accept(t); }; } }
@FunctionalInterface public interface Predicate<T> { boolean test(T t); default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } default Predicate<T> negate() { return (t) -> !test(t); } static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); } }
Predicate函數式接口定義了test抽象方法,它會對T對象執行判斷邏輯,並返回布爾類型的判斷接口。性能
仍是以ArrayList中的一個使用場景爲例。ArrayList中提供了一個removeIf方法,該方法傳入了Predicate接口,並利用該接口判斷是否要刪除這個對象:
public boolean removeIf(Predicate<? super E> filter) { checkNotNull(filter); E[] newArray = null; int newIndex = 0; for (int index = 0; index < array.length; ++index) { E e = array[index]; //使用Predicate的test方法判斷是否要刪除該對象 if (filter.test(e)) { if (newArray == null) { newArray = ArrayHelper.clone(array, 0, index); newIndex = index; } } else if (newArray != null) { newArray[newIndex++] = e; } } if (newArray == null) { return false; } array = newArray; return true; }
固然了,同Consumer同樣,它也提供了不少能夠傳入基礎類型的Predicate接口,如IntPredicate,DoublePredicate等
@FunctionalInterface public interface Function<T, R> { R apply(T t); default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } static <T> Function<T, T> identity() { return t -> t; } }
Function中定義了apply抽象方法,該抽象方法會接受一個T類型的對象,並轉化爲R類型的對象返回。使用方法和上面也沒啥區別,這裏就不具體贅述了。固然了,Function也爲基礎類型作了不少擴展,好比IntToDoubleFunction就能夠將int轉化爲double型,還有ToDoubleFunction<T>則支持將T對象轉化爲double基礎型。
複合Lambda表達式是指將多個同類型的Lambda表達式按照必定語法進行組合,生成新的Lambda表達式。以比較基礎的Predicate做爲例子。Predicate中有如下幾個默認方法:and,negate,or
,分別對應與,否認和或。
舉個例子,如今有兩個Predicate分別是判斷訂單的狀態是否爲已支付以及訂單的實付金額是否大於100。兩個Predicate以下:
Predicate<Order> p1 = (Order o) -> o.isPaid; Predicate<Order> p2 = (Order o) -> o.actualFee > 100;
假如如今想要判斷是已支付且實付金額大於100的訂單,則新的Predicate能夠經過上面兩個Predicate組合生成,利用and默認方法:
Predicate<Order> p3 = p1.and(p2);