Function函数式接口
关于什么是Function,这里就不做介绍了。我们就需要知道Function是jdk8提供的一个默认接口。从Function名字,我们就可以看出来Function接口就是指的是一个函数接口。那么就可以映射到数学上面来说函数的解释:函数就是指给定一个参数返回一个结果(一对一,多对一的映射关系)
这里就给出Function的源码:
@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()
该方法也是申明该函数具体执行什么样的操作,同时Function接口也给我们提供了两个默认方法和一个静态方法。
用Function能给我们干什么?
下面就通过一个简单的例子,来演示怎么使用Function接口为我们做事情。
例子:我们需要将输入一个数据,并给该数据进行一系列的操作输出。
public class Demo2 {
public static void main(String[] args) {
//执行平方操作
System.out.println(method1(2,(Integer a) -> a*a));
//将输入参数都加10
System.out.println(method1(2,a->a+10));
}
public static Integer method1(Integer a,Function<Integer,Integer> function){
return function.apply(a);
}
}
我们仔细分析上面的代码:可以发现,我们就只需要定义一个方法,而该方法就只是调用了Function的apply方法,但是并没有具体在方法定义的时候给出Function接口中的apply方法的具体实现,而是在方法调用的时候对方法进行实现,从而可以定义一个方法为我们做出许多不同的事情,这就是函数式接口也就是函数编程的一大优点,可以在方法中传递行为或者返回行为
上面已经对apply方法进行了介绍,那么接下来我们就介绍下两个默认方法的作用
Function中的compose方法
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
通过这个方法,我们可以发现,该方法接收一个Function类型的参数,并返回一个Function类型的结果。
我们来仔细的研读这句代码:(V v) -> apply(before.apply(v))。对于该句代码的执行过程:
- 首先调用before的apply方法,并传递一个初始参数
- 然后再执行该接口中的apply方法,并把before.apply执行的结果作为输入参数
- 通过lambda表达式实例化一个新的Function类型并实现apply方法,方法的实现就是返回apply(before.apply(v))的结果
由于不是特别好理解,就举一个例子:
public class Demo2 {
public static void main(String[] args) {
Function<Integer,Integer> function1 = value -> value*3;
Function<Integer,Integer> function2 = value -> value*value;
System.out.println(method1(2,function1,function2));
}
public static Integer method1(int a, Function<Integer,Integer> function1, Function<Integer,Integer> function2){
return function1.compose(function2).apply(a);
}
}
//output:12
通过这段代码,我们可以发现该代码输出的结果为12,那么为什么是12呢?我们就来仔细的研读:
- 按上面说的分析,首先先执行function2.apply(2),
而关于function2的apply方法以及被实现为:
apply(value){
return value * value;
}
- 再function1中的apply方法,并把function1.apply(2)的值传入给function1的apply方法
而关于function1的apply方法以及被实现为:
apply(value){
return value * 3;
}
- 然后再通过lambda表达式把计算的结果作为一个新Function类型的实例来实现apply方法
新的Function类型实例的apply方法:
apply(value){
return function1.apply计算的最终结果
}
关于compose方法的为什么会规定输入Function类型的第二个泛型必须是调用者Function类型第一个泛型类型的子类型。
下面给出解答:
public class Demo2 {
public static void main(String[] args) {
Function<Number,Integer> function1 = value -> (int)value;//T:Number R:Integer
Function<String,Integer> function2 = value -> Integer.parseInt(value);//T2:String R2:Integer ====>规定R2必须是T类型
System.out.println(method1(2,function1,function2));
}
public static Number method1(int a, Function<Number,Integer> function1, Function<String,Integer> function2){
return function1.compose(function2).apply("2");
}
}
通过这个程序我们就可以发现:
由于function1.compose(function2).apply("2")
底层是先执行function2.apply(2)
,然而function2.apply(2)
的输出类型R就是function1.apply(function2.apply(2))
输入,恰好又定义了function2的输出类型R又是function1的输入类型T的子类型或T类型。
Function中的andThen方法
通过源码分析,andThen方法和compose方法相反:
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
- 1.先执行调用andThen的Function类型的apply方法
- 2.再执行andThen接收的Function类型参数类型的apply方法,并把第一步计算结果作为输入
- 3.生成新的Function类型,并且新Function类型的apply方法的实现是直接返回第二步计算的过的值。
BiFunction函数接口
该函数接口就是接收两个参数,最终输出操作后的结果
@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));
}
}
通过源码发现,该接口只有一个抽象方法apply是接收两个参数,输出一个值。还有一个默认方法就是andThen方法。仔细观察,为什么没有和上面Function接口中的compose方法呢?
通过上面已经解释了,andThen方法是先执行调用者的apply方法,再执行接受者参数的apply方法。而compose方法是先执行参数的apply方法,后执行调用者的apply方法。由于BiFunction是接收两个参数,只有先执行调用者的apply方法才能接收两个参数。而如果是直接先执行Function类型参数的apply方法是不能接收两个参数的。因此,在BiFunction方法中就只有一个andThen方法的。
Consumer接口
Consumer通过名字一样可以知道为消费者。也就是说该接口的主要功能就是传入数据,而不输出任何数据处理。
@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);
};
}
}
通过上面的源码分析,就可以发现:Consumer有一个抽象方法就是accept(该方法就是让用户来给定该消费者如何消费传入的数据),还有一个andThen方法。
Consumer的andThen方法:
default Consumer<T> andThen(Consumer<? super T> var1) {
Objects.requireNonNull(var1);
return (var2) -> {
this.accept(var2);
var1.accept(var2);
};
}
通过该源码分析:andThen接收一个Consumer类型的参数。关于该方法执行的原理分析:
- 1.首先先执行调用者中的accept方法
- 2.然后在执行Consumer参数类型的accept方法
- 3.创建一个新的Consumer类型,并且accept方法中的实现是:把1 2 步的操作合起来(也就是把1和2的操作作为新Consumer类型的accept方法的实现)。
Supplier 接口
首先贴出源代码:
/**
* Represents a supplier of results.
*
* <p>There is no requirement that a new or distinct result be returned each
* time the supplier is invoked.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #get()}.
*
* @param <T> the type of results supplied by this supplier
*
* @since 1.8
*/
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
通过上面给出的源码以及注释我们就可以很明确的知道Supplier接口和Consumer相对应,我们可以把Supplier当做生产者 ,Supplier
接口当中的抽象方法是不接受参数,最后给我们返回一个值。
Supplier例子:
public class TestSuplier {
public static void main(String[] args) {
TestSuplier demo = new TestSuplier();
System.out.println(demo.createString(()->"hello world;"));
}
public String createString(Supplier<String> supplier){
return supplier.get();
}
}
Predicate接口
同理:我们先给出该接口的源代码:
/**
* Represents a predicate (boolean-valued function) of one argument.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #test(Object)}.
*
* @param <T> the type of the input to the predicate
*
* @since 1.8
*/
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(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 {@code false}, then the {@code other}
* predicate is not evaluated.
*
* <p>Any exceptions thrown during evaluation of either predicate are relayed
* to the caller; if evaluation of this predicate throws an exception, the
* {@code other} predicate will not be evaluated.
*
* @param other a predicate that will be logically-ANDed with this
* predicate
* @return a composed predicate that represents the short-circuiting logical
* AND of this predicate and the {@code other} predicate
* @throws NullPointerException if other is null
*/
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.
*
* @return 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 {@code true}, then the {@code other}
* predicate is not evaluated.
*
* <p>Any exceptions thrown during evaluation of either predicate are relayed
* to the caller; if evaluation of this predicate throws an exception, the
* {@code other} predicate will not be evaluated.
*
* @param other a predicate that will be logically-ORed with this
* predicate
* @return a composed predicate that represents the short-circuiting logical
* OR of this predicate and the {@code other} predicate
* @throws NullPointerException if other is null
*/
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)}.
*
* @param <T> the type of arguments to the predicate
* @param targetRef the object reference with which to compare for equality,
* which may be {@code null}
* @return 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);
}
}
通过对上面源代码进行简单的分析,我们可以发现,该接口有一个抽象方法,该抽象方法是test()
方法,从该方法和注释可以看出来,该抽象方法是用来传入一个值,返回一个boolean值,就可以知道该方法最主要的作用就是用来对传入的数据进行一系列的操作给出一个“是否”来作为判断条件。而关于对传入的直进行什么判断就得由用户自己进行确定。
例子:
public class TestPredicate {
public static void main(String[] args) {
TestPredicate demo = new TestPredicate();
System.out.println(demo.isOrNo(str->str.length()>5,"hello world;"));
}
public boolean isOrNo(Predicate<String> predicate,String param){
return predicate.test(param);
}
}
通过这个示例代码:我们就可以很清楚的知道,test方法的作用是什么啦(就是由用户确定对输入参数的判断方式,最终给出判断的结果是否为真/假)
and方法详解
/**
* 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 {@code false}, then the {@code other}
* predicate is not evaluated.
*
* <p>Any exceptions thrown during evaluation of either predicate are relayed
* to the caller; if evaluation of this predicate throws an exception, the
* {@code other} predicate will not be evaluated.
*
* @param other a predicate that will be logically-ANDed with this
* predicate
* @return a composed predicate that represents the short-circuiting logical
* AND of this predicate and the {@code other} predicate
* @throws NullPointerException if other is null
*/
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
通过and方法的实现,我们可以非常清楚的知道and方法就是我们经常使用的&&
运算符操作。也就是一种短路操作。
例子:
public class TestPredicate {
public static void main(String[] args) {
TestPredicate demo = new TestPredicate();
System.out.println(demo.isOrNo(str->str.length()>5,str->str.length()<10,"hello world;"));
}
public boolean isOrNo(Predicate<String> predicate,Predicate<String> predicate2,String param){
return predicate.and(predicate2).test(param);
}
}
上面的方法就是判断给定一个字符串,判断该字符串的长度是否大于5并且小于10;
or方法
/**
* 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 {@code true}, then the {@code other}
* predicate is not evaluated.
*
* <p>Any exceptions thrown during evaluation of either predicate are relayed
* to the caller; if evaluation of this predicate throws an exception, the
* {@code other} predicate will not be evaluated.
*
* @param other a predicate that will be logically-ORed with this
* predicate
* @return a composed predicate that represents the short-circuiting logical
* OR of this predicate and the {@code other} predicate
* @throws NullPointerException if other is null
*/
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
该方法就是我们传统开发时所遇到的||
运算符。是对给定的参数进行多个条件判断取或运算。
negate方法
/**
* Returns a predicate that represents the logical negation of this
* predicate.
*
* @return a predicate that represents the logical negation of this
* predicate
*/
default Predicate<T> negate() {
return (t) -> !test(t);
}
该方法就是对输入的参数的进行test方法后的结果取反 的操作。
isEqual方法
/**
* Returns a predicate that tests if two arguments are equal according
* to {@link Objects#equals(Object, Object)}.
*
* @param <T> the type of arguments to the predicate
* @param targetRef the object reference with which to compare for equality,
* which may be {@code null}
* @return 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
中的静态方法,该方法的作用就是对输入的参数进行判断是否相等的操作。
例子:
public class TestPredicate {
public static void main(String[] args) {
TestPredicate demo = new TestPredicate();
System.out.println(demo.isEquals(null,"hello"));
}
public boolean isEquals(String param1,String param2){
return Predicate.isEqual(param1).test(param2);
}
}