看此文前,不熟悉函数式编程和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);