@FunctionalInterface interfaceCalculator{ intcal(int a, int b); }
publicclassHelloWorld{ publicstaticvoidmain(String[] args){ Calculator c = (a, b) -> a + b; System.out.println(c.cal(1, 2)); c = (a, b) -> a * b; System.out.println(c.cal(1, 2)); } }
Lambda 形式
Lambda 表达式的基本形式如下所示:
1
(argument list) -> code
下面是一个例子:
如上所示: Lambda 表达式包含三个部分:
参数列表(A list of parameters) - 上图中为 (Apple a1, Apple a2)
箭头(An arrow) - 把参数列表和 Lambda 主体分隔开
Lambda 主体(The body of the lambda) - 上图中为 a1.getWeight().compareTo(a2.getWeight()),该 Lambda 主体会返回 compareTo 的结果。
@FunctionalInterface interfaceCalculator{ intcal(int a, int b); }
下面是使用 lambda 表达式以及匿名类来创建 Calculator 对象的示例代码。在下面的代码中对象 c 和 c2 的实现是等价的。
1 2 3 4 5 6 7 8 9 10
publicvoiddemo(){ Calculator c = (int a, int b) -> a + b;
Calculator c2 = new Calculator() { @Override publicintcal(int a, int b){ return a + b; } }; }
从上面的例子中,我们可以看到 Lambda 表达式 是和函数式接口中的 抽象方法 进行匹配的,其中 Lambda 表达式中参数匹配 cal 方法的参数,Lambda body 的内容作为抽象方法的具体实现,Lambda body 的计算值作为方法的返回值。这也是为什么要求函数式接口只能有一个抽象方法的原因。
@FunctionalInterface interfaceThrowExceptionInterface{ voidrun(int a, int b); }
publicclassLambdaTest{
publicvoidthrowException(){ // 这里编译时会报 Unhandled Exception:java.io.Exception ThrowExceptionInterface t = (int a, int b) -> { thrownew IOException(); }; } }
其实也很好理解,Lambda body 中的内容会作为抽象方法的具体实现,在方法中抛出了异常但是方法声明中却没有相关的异常声明,编译器肯定要报错的。
Lambda 表达式会赋值给 Calculator 对象,那么该 Lambda 表达式对应的目标类型就是 Calculator 接口,该接口中的 cal 方法对应的函数描述符为 (int, int) -> int,这个和 (int a, int b) -> a + b 可以匹配,这样就完成了类型检查。下图是一个完整的例子:
/** * Represents a predicate (boolean-valued function) of one argument. */ @FunctionalInterface publicinterfacePredicate<T> {
/** * Evaluates this predicate on the given argument. * * @param t the input argument * @return true if the input argument matches the predicate, * otherwise false */ booleantest(T t);
/** * Returns a composed predicate that represents a short-circuiting logical * AND of this predicate and another. When evaluating the composed * predicate, if this predicate is false, then the other * predicate is not evaluated. */ default Predicate<T> and(Predicate<? super T> other){ Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); }
/** * Returns a predicate that represents the logical negation of this * predicate. */ default Predicate<T> negate(){ return (t) -> !test(t); }
/** * Returns a composed predicate that represents a short-circuiting logical * OR of this predicate and another. When evaluating the composed * predicate, if this predicate is true, then the other * predicate is not evaluated. */ default Predicate<T> or(Predicate<? super T> other){ Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); }
/** * Returns 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); } }
我们看到在 Predicate 类中,除了 test 方法,还定义了三个 default 方法,and, or 和 negate,它们分别对应逻辑运算中的与(&&)、或(||)、非(!)操作。通过这三个方法,我们可以构造更复杂的 predicate 表达式:
1 2 3 4 5 6 7 8
publicvoidtestPredicate(){ String text = "111"; Predicate<String> a = s - > s != null; Predicate<String> b = s - > s.length() > 3; System.out.println(judge(text, a.and(b))); System.out.println(judge(text, a.negate())); System.out.println(judge(text, a.or(b))); }
对应的输出结果为:
1 2 3
false false true
另外 and 和 or 方法是按照在表达式链中的位置,从左向右确定优先级的。因此 a.or(b).and(c) 可以看作 (a || b) && c。
/** * Represents a predicate (boolean-valued function) of two arguments. This is * the two-arity specialization of {@link Predicate}. */ @FunctionalInterface publicinterfaceBiPredicate<T, U> {
booleantest(T t, U u);
default BiPredicate<T, U> and(BiPredicate<? super T, ? super U> other){ Objects.requireNonNull(other); return (T t, U u) -> test(t, u) && other.test(t, u); }
/** * Represents an operation that accepts a single input argument and returns no * result. Unlike most other functional interfaces, Consumer is expected * to operate via side-effects. */ @FunctionalInterface publicinterfaceConsumer<T> {
/** * Performs this operation on the given argument. * * @param t the input argument */ voidaccept(T t);
/** * Returns a composed Consumer that performs, in sequence, this * operation followed by the after operation. If performing either * operation throws an exception, it is relayed to the caller of the * composed operation. If performing this operation throws an exception, * the after operation will not be performed. */ default Consumer<T> andThen(Consumer<? super T> after){ Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }
publicvoidtestConsume(){ StringBuilder builder = new StringBuilder(); Consumer <StringBuilder> a = s -> s.append("abcd"); Consumer <StringBuilder> b = s -> s.reverse(); Consumer <StringBuilder> c = s -> s.append("1234"); consume(builder, a.andThen(b).andThen(c)); System.out.println(builder.toString()); }
/** * Represents an operation that accepts two input arguments and returns no * result. This is the two-arity specialization of Consumer. * Unlike most other functional interfaces, BiConsumer is expected * to operate via side-effects. */ @FunctionalInterface publicinterfaceBiConsumer<T, U> {
voidaccept(T t, U u);
default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after){ Objects.requireNonNull(after);
/** * Represents a function that accepts one argument and produces a result. */ @FunctionalInterface publicinterfaceFunction<T, R> {
/** * Applies this function to the given argument. */ R apply(T t);
/** * Returns a composed function that first applies the before * function to its input, and then applies this function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. */ default <V> Function<V, R> compose(Function<? super V, ? extends T> before){ Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); }
/** * Returns a composed function that first applies this function to * its input, and then applies the after function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. */ default <V> Function<T, V> andThen(Function<? super R, ? extends V> after){ Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); }
/** * Returns a function that always returns its input argument. */ static <T> Function<T, T> identity(){ return t -> t; } }
publicvoidtestFunction(){ Function<Integer, Integer> f = x -> x + 1; Function<Integer, Integer> g = x -> x * 2; int i = func(1, f.andThen(g)); // 输出 4 System.out.println(i);
i = func(1, f.compose(g)); // 输出 3 System.out.println(i); }
UnaryOperator
UnaryOperator 是一种特殊的 Function,表示操作数和返回值是同一种类型,函数描述符为 T -> T。下面是该接口的定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/** * Represents an operation on a single operand that produces a result of the * same type as its operand. This is a specialization of {@code Function} for * the case where the operand and result are of the same type. */ @FunctionalInterface publicinterfaceUnaryOperator<T> extendsFunction<T, T> {
/** * Returns a unary operator that always returns its input argument. */ static <T> UnaryOperator<T> identity(){ return t -> t; } }
下面是一个使用示例:
1 2 3 4
publicvoidtestUnaryOperator(){ UnaryOperator<Integer> u = x -> x + 1; System.out.println(u.apply(1)); }
/** * Represents a function that accepts two arguments and produces a result. * This is the two-arity specialization of Function. */ @FunctionalInterface publicinterfaceBiFunction<T, U, R> {
/** * Applies this function to the given arguments. * * @param t the first function argument * @param u the second function argument * @return the function result */ R apply(T t, U u);
/** * Returns a composed function that first applies this function to * its input, and then applies the {@code after} function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. */ default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after){ Objects.requireNonNull(after); return (T t, U u) -> after.apply(apply(t, u)); } }
下面是一个使用示例:
1 2 3 4 5
publicvoidtestBiFunction(){ BiFunction<Integer, Double, String> b = (i, d) -> String.valueOf(i + d); String r = b.apply(1, 2.5); System.out.println(r); }
/** * Represents an operation upon two operands of the same type, producing a result * of the same type as the operands. This is a specialization of * BiFunction for the case where the operands and the result are all of * the same type. */ @FunctionalInterface publicinterfaceBinaryOperator<T> extendsBiFunction<T,T,T> { /** * Returns a BinaryOperator which returns the lesser of two elements * according to the specified Comparator. */ publicstatic <T> BinaryOperator<T> minBy(Comparator<? super T> comparator){ Objects.requireNonNull(comparator); return (a, b) -> comparator.compare(a, b) <= 0 ? a : b; }
/** * Returns a BinaryOperator which returns the greater of two elements * according to the specified Comparator. */ publicstatic <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator){ Objects.requireNonNull(comparator); return (a, b) -> comparator.compare(a, b) >= 0 ? a : b; } }
下面是一个使用示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
publicvoidtestBinaryOperator(){ BinaryOperator<Integer> b = (x, y) -> x + y; int z = b.apply(1, 3); System.out.println(z);
BinaryOperator<Integer> min = BinaryOperator.minBy((x, y) -> x - y); // 输出 1 z = min.apply(1, 3); System.out.println(z);
// 输出 3 BinaryOperator<Integer> max = BinaryOperator.maxBy((x, y) -> x - y); z = max.apply(1, 3); System.out.println(z); }
Primitive specializations
在上面提到的接口中,都是接受泛型参数,我们知道泛型参数只能是引用类型,也就是说对于 int 这样的基本类型,我们要首先装箱(boxing)成 Integer 类型,在使用的时候再拆箱(unboxing)成 int。虽然 Java 提供了自动装箱机制,但是在性能方面是要付出代价的。所以对于上述的函数式接口,Java 8 提供了针对基本类型的版本,以此来避免输入输出是基本类型时的自动装箱操作。以 Predicate 为例,假设我们要检测一个 int 是否满足某个条件,我们可以使用 IntPredicate :
1 2 3 4 5
publicvoidtestIntPredicate(){ IntPredicate ip = x -> x > 3; boolean r = ip.test(4); System.out.println(r); }
/** * Represents a predicate (boolean-valued function) of one {@code int}-valued * argument. This is the {@code int}-consuming primitive type specialization of * {@link Predicate}. */ @FunctionalInterface publicinterfaceIntPredicate{