Java基础知识之函数式接口

136 阅读3分钟

1.定义

函数式接口简单的来说就是使用'@FunctionalInterface'注解并且只包含一个抽象方法的接口

2.示例

jdk中的Runnable就是一个函数式接口,它的签名如下:

Runnable定义.png

我们在使用时的声明初始化如下:

Runnable声明初始化.png

接下来,自定义一个函数式接口:

关于接口的一个链接

@FunctionalInterface
public interface MyFunctionalInterface {
    void method();
}

它的声明初始化如下:

MyFunctionalInterface myFunctionalInterface = new MyFunctionalInterface() {
    @Override
    public void method() {
        System.out.println("这是自定义的一个函数式接口");
    }
};
MyFunctionalInterface myFunctionalInterface2 = () -> {
    System.out.println("这是自定义函数式接口的简化初始化方式");
};

3.jdk中的一些函数式接口

3.1.Consumer<T>

消费型的接口

它的签名如下:

Consuer.png 简单示例如下:

1.首先定义一个形参为Consumer的方法

void testConsumer(Consumer<String> consumer,String arg){
    consumer.accept(arg);
}

2.调用

//第一种调用
testConsumer(new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s+"1");
    }
}, "aaa");
//第二种调用(简化)
testConsumer(arg-> System.out.println(arg+"2"),"bbb");

在调用中下面是上面的简化写法(首先要明确的是函数式接口可以作为函数的实参进行传递,因此有了上面的写法),简化是根据函数式接口中的抽象方法来简化的,只有一个参数,就写一个参数名,然后->,如果抽象方法的实现只有一行代码可以不写大括号和return

3.andThen(Consumer<? extents T> after)解析

andThen方法的形参是Consumer函数式接口,返回一个Consumer对象,因此可以连续使用n个andThen方法,每一次调用内部执行了对应andThen方法中consumer形参的accept方法.

具体的简单示例如下:

void testConsumer(Consumer<String> consumer,Consumer<String> consumer2,Consumer<String> consumer3,String arg){
    consumer.andThen(consumer2).andThen(consumer3).accept(arg);
}
void testConsumer2(Consumer<Integer> consumer,int a){
    consumer.andThen(consumer).andThen(consumer).accept(a);
}


testConsumer(arg-> System.out.println(arg+"1"),a-> System.out.println(a+"2"),a-> System.out.println(a+"3"),"bbb");
testConsumer2(a->{
    a++;
    System.out.println(a);
    },1);

需要注意的是函数式接口Consumer中的accept方法的返回值是void的,因此不会产生重复调用的结果累加,每次andThen中的操作都是对最原始数据的一种消费.

3.2.Supplier<T>

供给型接口,无传入参数,生产一个指定泛型类型的数据

它的定义如下:

Supplier.png

简单示例如下:

1.首先定义一个形参为Supplier的函数

这里说明一点,在定义函数的时候可以指定泛型,并在Supplier处引用该泛型Supplier<T> supplier,这样使得程序的多态性更加的丰富

int[] testSupplier(Supplier<Integer> supplier,int length){
    int[] nums = new int[length];
    for (int i = 0; i < length; i++) {
        nums[i] = supplier.get();
    }
    return nums;
}

2.调用

final int[] ints = testSupplier(new Supplier<Integer>() {
    @Override
    public Integer get() {
        return new Random().nextInt(100);
    }
}, 10);
System.out.println(Arrays.toString(ints));
//是上面的简化写法,只有一行代码的时候,可以不用写return
final int[] ints1 = testSupplier(() -> new Random().nextInt(200), 10);
System.out.println(Arrays.toString(ints1));

3.3Function<T,R>

转换型接口,它的抽象方法apply传入一个T类型的参数,返回一个R类型的结果

它的签名如下:

Function.png

1.定义一个形参为Function的函数

Integer testFunction(Function<String,Integer> function,String str){
    return function.apply(str);
}

2.调用

final Integer integer = testFunction((String a) -> Integer.parseInt(a), "12");
System.out.println(integer.intValue());

方法compose,andthen解析(待完成)

4.Predicate<T>

断言型函数式接口,抽象方法test(T t)接口一个参数,判断该参数是否符合某种规则,符合为true,不符合为false,用于过滤

它的签名如下:

Predicate.png

1.定义一个形参为Predicate的方法

//传入一个list集合
static List<String> testPredicate(Predicate<String> predicate,List<String> list){
    List<String> newList = new LinkedList();
    for (String s : list) {
        if (predicate.test(s)) {
            newList.add(s);
        }
    }
    return newList;
}

2.调用

List<String> list = Arrays.asList("a","b","c","aa","bb","cc","dd");
final List<String> list1 = testPredicate(a -> a.length() > 1, list);
System.out.println(list1);

方法and,or,isEqual,not,negate解析(待完成)

总结:函数式结果总共分为四类,消费性(Consumer),供给型(Supplier),转换型(Function),断言型(Predicate),为了方便记忆,总结为下面的简短语 肯(Consumer)消费,私(Supplier)供给,发(Function)转换,皮(Predicate)断言

个人理解:这四种函数式接口都是定义了某个规则用于程序调用,所以可以不在方法形参处声明,可以在类中直接定义某种规则等其他的方式,用于后续的逻辑判断,示例如下:

class Rule{
    public static final Function<String, Integer> function = new Function<>() {
        @Override
        public Integer apply(String str) {
            return Integer.parseInt(str);
        }
    };
}

调用如下:

final Integer intResult = Rule.function.apply("12");
System.out.println(intResult);