java8 的java.util.function包中函数式接口
《java8 的java.util.function包中函数式接口》
包括:
一. Function 接口的使用
// T 是传入参数
// R 是返回参数
@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));
}
//Returns a function that always returns its input argument.
static <T> Function<T, T> identity() {
return t -> t;
}
}
public class TestFunction { public static void main(String[] args) { Function<Integer, Integer> incr1 = x -> x + 1; Function<Integer, Integer> multiply = x -> x * 2; int x = 2; System.out.println("f(x)=x+1,when x=" + x + ",f(x)=" + incr1.apply(x)); System.out.println("f(x)=x+1,g(x)=2x,when x=" + x + ",f(g(x))=" + incr1.compose(multiply).apply(x)); System.out.println("f(x)=x+1,g(x)=2x,when x=" + x + ",g(f(x))=" + incr1.andThen(multiply).apply(x)); System.out.println("compose vs andThen:f(g(x))" + incr1.compose(multiply).apply(x) + "," + multiply.andThen(incr1).apply(x)); } }
运行结果:
f(x)=x+1,when x=2,f(x)=3 f(x)=x+1,g(x)=2x,when x=2,f(g(x))=5 f(x)=x+1,g(x)=2x,when x=2,g(f(x))=6 compose vs andThen:f(g(x))5,5
- 定义 validInput 方法,传入 function 接口,然后在该方法中定义 function.apply(name),也就是说,传入一个 name 参数,应用某些规则,返回一个结果,至于是什么规则,先不定义。
- 在main 方法中调用 validInput(name,inputStr ...),这里我们定义规则,利用lambda 表达式, 规则是:传入一个 inputStr 字符串,如果为空,返回 xx;否则 返回 xx。
1.2、 Function高阶函数
@FunctionalInterface public interface BiFunction<T, U, R> { R apply(T t, U u); 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)); } }
比如这个函数定义,参数是z,返回值是一个Function,这个Function本身又接受另一个参数y,返回z+y。于是我们可以根据这个函数,定义任意加法函数:
由于高阶函数接受一个函数作为参数,结果返回另一个函数,所以是典型的函数到函数的映射。
BiFunction提供了二元函数的一个接口声明,举例来说:
其输出结果将是:f(z)=x*y, when x=3,y=5, then f(z)=15。
二元函数没有compose能力,只是默认实现了andThen。
有了一元和二元函数,那么可以通过组合扩展出更多的函数可能。
Function接口相关的接口包括:
BiFunction :R apply(T t, U u);接受两个参数,返回一个值,代表一个二元函数;
DoubleFunction :R apply(double value);只处理double类型的一元函数;
IntFunction :R apply(int value);只处理int参数的一元函数;
LongFunction :R apply(long value);只处理long参数的一元函数;
ToDoubleFunction:double applyAsDouble(T value);返回double的一元函数;
ToDoubleBiFunction:double applyAsDouble(T t, U u);返回double的二元函数;
ToIntFunction:int applyAsInt(T value);返回int的一元函数;
ToIntBiFunction:int applyAsInt(T t, U u);返回int的二元函数;
ToLongFunction:long applyAsLong(T value);返回long的一元函数;
ToLongBiFunction:long applyAsLong(T t, U u);返回long的二元函数;
DoubleToIntFunction:int applyAsInt(double value);接受double返回int的一元函数;
DoubleToLongFunction:long applyAsLong(double value);接受double返回long的一元函数;
IntToDoubleFunction:double applyAsDouble(int value);接受int返回double的一元函数;
IntToLongFunction:long applyAsLong(int value);接受int返回long的一元函数;
LongToDoubleFunction:double applyAsDouble(long value);接受long返回double的一元函数;
LongToIntFunction:int applyAsInt(long value);接受long返回int的一元函数;
1.3、Operator
Operator其实就是Function,函数有时候也叫作算子。算子在Java8中接口描述更像是函数的补充,和上面的很多类型映射型函数类似。
算子Operator包括:UnaryOperator和BinaryOperator。分别对应单元算子和二元算子。
算子的接口声明如下:
二元算子的声明:
很明显,算子就是一个针对同类型输入输出的一个映射。在此接口下,只需声明一个泛型参数T即可。对应上面的例子:
例子里补充一点的是,BinaryOperator提供了两个默认的static快捷实现,帮助实现二元函数min(x,y)和max(x,y),使用时注意的是排序器可别传反了:)
其他的Operator接口:(不解释了)
LongUnaryOperator:long applyAsLong(long operand);
IntUnaryOperator:int applyAsInt(int operand);
DoubleUnaryOperator:double applyAsDouble(double operand);
DoubleBinaryOperator:double applyAsDouble(double left, double right);
IntBinaryOperator:int applyAsInt(int left, int right);
LongBinaryOperator:long applyAsLong(long left, long right);
二、Consumer
/** * Performs this operation on the given argument. * * @param t the input argument */ void accept(T t); default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; }
public class Test8Consumer { public static void main(String[] args) { Consumer<Integer> consumer = System.out::println; consumer.accept(100); //use function, you always need one return value Function<Integer, Integer> function = x -> { System.out.println(x); return x; }; function.apply(100); } }
结果:
100 100
三、 Predicate 接口
@FunctionalInterface public interface Predicate<T> { /** * 具体过滤操作 需要被子类实现. * 用来处理参数T是否满足要求,可以理解为 条件A */ boolean test(T t); /** * 调用当前Predicate的test方法之后再去调用other的test方法,相当于进行两次判断 * 可理解为 条件A && 条件B */ default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } /** * 对当前判断进行"!"操作,即取非操作,可理解为 ! 条件A */ default Predicate<T> negate() { return (t) -> !test(t); } /** * 对当前判断进行"||"操作,即取或操作,可以理解为 条件A ||条件B */ default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); } /** * 对当前操作进行"="操作,即取等操作,可以理解为 A == B */ static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); } }
其默认方法也封装了and、or和negate逻辑。
predicate示例1:
public static void main(String[] args) { /** * 1、判断数字是否大于7 */ //设置一个大于7的过滤条件 Predicate<Integer> predicate = x -> x > 7; System.out.println(predicate.test(10)); //输出 true System.out.println(predicate.test(6)); //输出 fasle /** * 2、大于7并且 */ //在上面大于7的条件下,添加是偶数的条件 predicate = predicate.and(x -> x % 2 == 0); System.out.println(predicate.test(6)); //输出 fasle System.out.println(predicate.test(12)); //输出 true System.out.println(predicate.test(13)); //输出 fasle /** * 3、add or 简化写法 */ predicate = x -> x > 5 && x < 9; System.out.println(predicate.test(10)); //输出 false System.out.println(predicate.test(6)); //输出 true }
示例predicate2:
import java.util.function.Predicate; public class Test3 { public static void main(String[] args) { String name = ""; String name1 = "12"; String name2 = "12345"; System.out.println(validInput3(name, inputStr -> !inputStr.isEmpty() && inputStr.length() <= 3)); System.out.println(validInput3(name1, inputStr -> !inputStr.isEmpty() && inputStr.length() <= 3)); System.out.println(validInput3(name2, inputStr -> !inputStr.isEmpty() && inputStr.length() <= 3)); } public static boolean validInput3(String name, Predicate<String> function) { return function.test(name); } }
Predicate在Stream中有应用,Stream的filter方法就是接受Predicate作为入参的。这个具体在后面使用Stream的时候再分析深入。
其他高阶Predicate接口:
BiPredicate:boolean test(T t, U u);接受两个参数的二元谓词
DoublePredicate:boolean test(double value);入参为double的谓词函数
IntPredicate:boolean test(int value);入参为int的谓词函数
LongPredicate:boolean test(long value);入参为long的谓词函数
四、Supplier(提供者)
最后说的是一个叫做Supplier的函数接口,其声明如下:
其简洁的声明,会让人以为不是函数。这个抽象方法的声明,同Consumer相反,是一个只声明了返回值,不需要参数的函数(这还叫函数?)。也就是说Supplier其实表达的不是从一个参数空间到结果空间的映射能力,而是表达一种生成能力,因为我们常见的场景中不止是要consume(Consumer)或者是简单的map(Function),还包括了new这个动作。而Supplier就表达了这种能力。
比如你要是返回一个常量,那可以使用类似的做法:
这保证supplier对象输出的一直是1。
如果是要利用构造函数的能力呢?就可以这样:
public class Test8Supplier { public static void main(String[] args) { Supplier<Test8Supplier> anotherSupplier; for(int i = 0; i < 10; i++) { anotherSupplier = Test8Supplier::new; System.out.println(anotherSupplier.get()); } } }
这样的输出可以看到,全部的对象都是new出来的。
这样的场景在Stream计算中会经常用到,具体在分析Java 8中Stream的时候再深入。
其他Supplier接口:
BooleanSupplier:boolean getAsBoolean();返回boolean
DoubleSupplier:double getAsDouble();返回double
IntSupplier:int getAsInt();返回int
LongSupplier:long getAsLong();返回long
五、Comparator(比较器)
@FunctionalInterface public interface Comparator<T> { /** * 比较方法逻辑 * @param o1 参数1 * @param o2 参数2 * @return 返回值大于0 ---> (o1 > o2) * 返回值等于0 ---> (o1 = o2) * 返回值小于0 ---> (o1 < o2) */ int compare(T o1, T o2); }
参考: