常用的函数式接口

常用的函数式接口

jdk提供了大量常用的函数式接口以丰富lambda的典型使用场景,它们主要在java.util.function包中被提高。

1.Supplier接口

java.util.function.Supplier<T>被称为为生产型接口,该接口仅包含一个无参的方法:T get();。用来获取一个泛型指定类型的对象数据。

public class TestSupplier {
    public static int getmessge(Supplier<Integer> supplier){
        return supplier.get();
    }
    public static void main(String[] args) {
        int[] array = {11,22,404,33,77};
        //使用lambda表达式获取数组中最大的值
        int maxValue = getmessge(() -> {
            int max = array[0];
            for (int i : array) {
                if (i > max) {
                    max = i;
                }
            }
            return max;
        });
        System.out.println(maxValue);
    }
}
/*print:404*/

2.Consumer接口

java.util.function.Consumer<T>接口与sipplier正好相反,他不是生产数据,而是消费数据,没有返回值,其数据类型由泛型决定。其抽象方法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 TestConsumer {
    public static void consumer(String s, Consumer<String> con1,Consumer<String> con2){
        con1.andThen(con2).accept(s);
    }

    public static void main(String[] args) {
        String message="talk is cheap";
        consumer(message,(s)->{
            String s1 = s.toUpperCase();
            System.out.println(s1);
        },(s)->{
            String s2 = s.substring(8);
            System.out.println(s2);
        });
    }
}
/* TALK IS CHEAP */
/* cheap */

Consumer还有多个其他的接口,具体有以下几种,在使用函数式接口时,若有提供具体类型的接口,就尽量使用此接口,因为具体的类型指定可以避免装箱拆箱时所带来的额外资源消耗

BiConsumer     接收两个参数

IntConsumer     接收一个int参数

LongConsumer     接收一个long参数

DoubleConsumer     收一个double参数

ObjIntConsumer     接收两个参数 T,int

ObjLongConsumer     接收两个参数 T,long

ObjDoubleConsumer    接收两个参数 T,,double

3.Predicate接口

java.util.function.Predicate<T>可以对某种数据类型的数据进行判断,从而得到一个boolean值结果。抽象方法为void test(T t),包含三个默认方法:

default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }
 default Predicate<T> negate() {
        return (t) -> !test(t);
    }

分别对应逻辑判断的“&&”,“||”,“!”

int[] numbers= {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
        List<Integer> list=new ArrayList<>();
        for(int i:numbers) {
            list.add(i);
        }
        Predicate<Integer> p1=i-> i>5;
        Predicate<Integer> p2=i-> i<20;
        Predicate<Integer> p3=i-> i%2==0;
        List test=list.stream().filter(p1.and(p2).and(p3)).collect(Collectors.toList());
        System.out.println(test.toString());
/* print:[6, 8, 10, 12, 14]*/

我们定义了三个断言p1,p2,p3。现在有一个从1~15的list,我们需要过滤这个list。上述的filter是过滤出所有大于5小于20,并且是偶数的列表。

假如突然我们的需求变了,我们现在需要过滤出奇数。那么我不可能直接去改Predicate,因为实际项目中这个条件可能在别的地方也要使用。那么此时我只需要更改filter中Predicate的条件。

List test=list.stream().filter(p1.and(p2).and(p3.negate())).collect(Collectors.toList());
/* print:[7, 9, 11, 13, 15]*/

4.Function接口

java.util.function.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));
    }

andThen跟compose正相反,先执行当前的逻辑,再执行传入的逻辑。

public void test(){
    Function<Integer,Integer> A=i->i+1;
    Function<Integer,Integer> B=i->i*i;
    System.out.println("F1:"+B.apply(A.apply(5)));
    System.out.println("F1:"+B.compose(A).apply(5));
    System.out.println("F2:"+A.apply(B.apply(5)));
    System.out.println("F2:"+B.andThen(A).apply(5));
}
/* F1:36 */
/* F1:36 */
/* F2:26 */
/* F2:26 */
posted @ 2020-10-10 23:33  深陈  阅读(285)  评论(0)    收藏  举报