简介
在函数式编程中函数可以在程序中传来传去,甚至数字也可以用函数表示,而在面向对象中必须将这些函数封装成方法,通过调用方法实现。所以 Java 从邻居那拿来了 Lambda。
Java8 引入了 Lambda 表达式,它使代码变得更简洁和高效,更方便的让我们在计算机上说话,长得就像下面那样。
s -> s + s;
(s1, s2) -> { return s1 + s2; };
Lambda可以用于实现只有一个抽象方法的接口,在接口加上 @FunctionalInterface 注解可以提醒我们接口只有一个抽象方法 。下面是 Java 的 Comparator 两种实现方式,以前的写法是实现一个匿名类。
//comparator2 更简洁
Comparator<String> comparator1 = (s1, s2) -> s1.compareTo(s2);
Comparator<String> comparator2 = String::compareTo;
几种常见函数
Java 本身提供了 Function、BiFunction、Predicate、Consumer、Supplier 等几种函数,介绍如下。
函数 | 格式 | 说明 |
---|---|---|
Function | Function<T, R> | 接收一个参数,有一个返回值 |
BiFunction | BiFunction<T, U, R> | 接收两个参数,有一个返回值 |
Predicate | Predicate<T> | 接收一个参数,返回值boolean类型 |
Consumer | Consumer<T> | 接收一个参数,没有返回值 |
Supplier | Supplier<T> | 没有参数,有一个返回值 |
Function
Function<T, R> 中 T 是传入参数的类型,R 是返回值的类型。源码中主要有 apply、compose、andThen 方法。
@FunctionalInterface
public interface Function<T, R> {
//执行函数
R apply(T t);
//先执行 before 函数,再执行当前函数。
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
//先执行当前函数,再执行 after 函数
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
}
示例如下。
Function<Integer, String> fun1 = integer -> String.valueOf(integer + integer);
Function<String, BigDecimal> fun2 = s -> new BigDecimal(s + ".5");
//执行函数
String s = fun1.apply(1);
//两个函数中都是 fun1 先执行
BigDecimal decimal1 = fun1.andThen(fun2).apply(1);
BigDecimal decimal2 = fun2.compose(fun1).apply(1);
执行后 s 值是 2,decimal1 和 decimal2 值是 2.5。
BiFunction
BiFunction<T, U, R> 中 T 和 U 是传入的参数类型,R 是返回值类型。源码中有 apply、andThen 方法,因为 BiFunction 需要两个参数,所以没有 compose 方法。
@FunctionalInterface
public interface BiFunction<T, U, R> {
//执行方法
R apply(T t, U u);
//先执行当前函数,再执行 after 函数
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));
}
}
示例如下。
BiFunction<Integer, Integer, String> biFunction = (param1, param2) -> String.valueOf(param1 * param2 + 1);
Function<String, BigDecimal> fun1 = s -> new BigDecimal(s + ".5");
//先执行 biFunction,再执行 fun1
BigDecimal decimal3 = biFunction.andThen(fun1).apply(1, 2);
Predicate
Predicate<T> 中 T 是 传入参数的类型,返回一个 boolean 类型的值。源码中主要有 test、and、negate、or、isEqual 方法。
@FunctionalInterface
public interface Predicate<T> {
//执行方法
boolean test(T t);
//关系运算符 &&,当 test 的结果为 false 时直接结束,不运算 other
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);
}
//关系运算符 ||,当 test 的结果为 true 时直接结束,不运算 other
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
//判断相等
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
示例如下。
//为空返回 true
Predicate<String> isNull = Objects::isNull;
//不为空返回 true
Predicate<String> nonNull = Objects::nonNull;
boolean bool = isNull.or(nonNull.negate()).and(Predicate.isEqual("123")).test("123");
执行后 bool 的值为 false,执行后 isNull.test() 为 false,nonNull.negate() 为 false,因为最后一个是 and,所以不需要判断 Predicate.isEqual("123"),最后得出 false || false 为 false。如果 and 之后还有 or 的话要接着判断。
Consumer
Consumer<T> 中 T 是传入参数的类型,没有返回值。源码中有 accept 和 andThen 方法。
@FunctionalInterface
public interface Consumer<T> {
//执行方法
void accept(T t);
//先执行当前函数,再执行 after 函数
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
示例如下。
Consumer<Integer> consumer1 = integer -> System.out.println(integer + 1);
Consumer<Integer> consumer2 = integer -> System.out.println(integer + 2);
//先执行 consumer1,再执行 consumer2
consumer1.andThen(consumer2).accept(1);
执行后控制台依次打印 2 和 3。
Supplier
Supplier<T> 中 T 是返回值的类型,没有传入的参数。源码中只有 get 方法。
@FunctionalInterface
public interface Supplier<T> {
//执行方法
T get();
}
示例如下。
Supplier<LocalDate> supplier = LocalDate::now;
//返回当前日期
LocalDate localDate = supplier.get();
System.out.println(localDate);
控制台打印当前日期时间 2020-05-31。
总结
本文对 Java8 中的 lambda 做了简单了解,介绍了 5 种函数,想熟练使用还需要实践(第一次写博客,有不足还请指正)。