Java之函数式接口源码解析

函数式接口

只包含一个抽象方法的接口,称为函数式接口。

你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda 表达式抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽象方法上进行声明)。

我们可以在一个接口上使用 @FunctionalInterface注解,这样做可以检查它是否是一个函数式接口。同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。

java.util.function包下定义了Java 8 的丰富的函数式接口

image-20200923165329350

我们查看Comparator接口源码。发现了一些矛盾的地方。

image-20200923165757180

我们发现了该接口中不止包含了一个方法,还存在大量的defaultstatic方法。这和上文的定义是矛盾的!!

在jdk8之前,interface之中可以定义变量和方法,变量必须是public、static、final的,方法必须是public、abstract的。由于这些修饰符都是默认的,JDK8及以后,允许我们在接口中定义static方法和default方法。

JDK8接口中的静态方法和默认方法,都不算是抽象方法。。接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。

image-20200923170228916

所以该接口的确是一个函数式接口!!

Java从诞生日起就是一直倡导“一切皆对象”,在Java里面面向对象(OOP) 编程是一切。但是随着python、scala等语言的兴起和新技术的挑战,Java不 得不做出调整以便支持更加广泛的技术要求,也即java不但可以支持OOP还 可以支持OOF(面向函数编程)

在函数式编程语言当中,函数被当做一等公民对待。在将函数作为一等公民的 编程语言中,Lambda表达式的类型是函数。但是在Java8中,有所不同。在 Java8中,Lambda表达式是对象,而不是函数,它们必须依附于一类特别的 对象类型——函数式接口。

简单的说,在Java8中,Lambda表达式就是一个函数式接口的实例。这就是 Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口 的实例,那么该对象就可以用Lambda表达式来表示。

所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。

**@**FunctionalInterface

image-20200923170602530

  1. 该注解只能标记在"有且仅有一个抽象方法"的接口上。

  2. JDK8接口中的静态方法和默认方法,都不算是抽象方法。

  3. 接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。

  4. 该注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。

自定义函数式接口

通过对函数式接口概念的认知,我们现在来自定义一个MyFunctionInterface 函数式接口测试。

只包含一个抽象方法

image-20200923171412859

//自定义函数式接口
public interface MyFunctionInterface<T> {

    //抽象方法
    T test(T t);
}

测试类TestFunction

image-20200923171514395

public class TestFunction {

    public static void main(String[] args) {
        MyFunctionInterface<String> function = (str) -> {
            return str;
        };

        System.out.println(function.test("FunctionInterface Test!"));
    }
}

包含一个覆盖Object方法

覆盖Object的 hashCode方法

image-20200923171729178

再次运行测试类,成功!说明它是一个函数式接口

image-20200923171514395

//自定义函数式接口
public interface MyFunctionInterface<T> {

    //抽象方法
    T test(T t);

    //覆盖Object方法
    int hashCode();
    
}

包含一个default方法

image-20200923172018308

//自定义函数式接口
public interface MyFunctionInterface<T> {

    //抽象方法
    T test(T t);

    //覆盖Object方法
    int hashCode();

    //默认方法
    public default void defaultMethod(){

    }

}

再次运行测试类,成功!说明它default不是抽象方法,该接口是一个函数式接口

image-20200923171514395

包含一个static方法

image-20200923185337449

public interface MyFunctionInterface<T> {

    //抽象方法
    T test(T t);

    //覆盖Object方法
    int hashCode();

    //默认方法
    public default void defaultMethod(){

    }

    //静态方法
    public static void staticMethod(){

    }
}

再次运行测试类,成功!说明它static不是抽象方法,该接口是一个函数式接口

image-20200923171514395

标注@FunctionInterface注解

通过前面的测试,我们可以明确知道,只要该接口只含有一个抽象方法,它就是一个函数式接口。而不是一定要标注@FunctionInterface注解,这两者之间没有绝对的联系。

该注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。

image-20200923185744315

//自定义函数式接口
@FunctionalInterface
public interface MyFunctionInterface<T> {

    //抽象方法
    T test(T t);

    //覆盖Object方法
    int hashCode();

    //默认方法
    public default void defaultMethod(){

    }

    //静态方法
    public static void staticMethod(){

    }
}

四大核心函数式接口

函数式接口参数类型返回类型用途
Consumer<T>消费型Tvoid对类型为T的对象应用操作,包含方法:void accept(T t)
Supplier<T>供给型T对类型为T的对象,包含方法:T get()
Function<T,R>函数型TR对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t)
Predicate<T>断定型Tboolean确定类型为T的对象是否满足某约束,并返回boolean值。包含方法boolean test(T t)

Consumer消费型

image-20200923192317870

@Test
public void test1(){

    happyTime(500, new Consumer<Double>() {
        @Override
        public void accept(Double aDouble) {
            System.out.println("学习太累了,去天上人间买了瓶矿泉水,价格为:" + aDouble);
        }
    });

    System.out.println("********************");

    happyTime(400,money -> System.out.println("学习太累了,去天上人间喝了口水,价格为:" + money));
}

public void happyTime(double money, Consumer<Double> con){
    con.accept(money);
}

image-20200923192400600

Supplier供给型

image-20200923193152964

@Test
public void test2() {

    System.out.println(get(new Supplier<String>() {
        @Override
        public String get() {
            return "犯罪人:张三";
        }
    }));

    System.out.println(get(() -> {
        return "法外狂徒三哥!";
    }));
}

public String get(Supplier<String> supplier) {
    return supplier.get();
}

image-20200923193220508

Function函数型接口

image-20200923193912896

@Test
public void test3() {
    System.out.println(getLength("test", new Function<String, Integer>() {
        @Override
        public Integer apply(String s) {
            return s.length();
        }
    }));

    System.out.println(getLength("lambda", str -> str.length()));
}

public int getLength(String s, Function<String, Integer> function) {
    return function.apply(s);
}

image-20200923193957077

Predicate断定型接口

image-20200923194231733

@Test
public void test4() {
    List<String> list = Arrays.asList("北京", "南京", "天津", "东京", "西京", "普京");

    List<String> filterStrs = filterString(list, new Predicate<String>() {
        @Override
        public boolean test(String s) {
            return s.contains("津");
        }
    });

    System.out.println(filterStrs);


    List<String> filterStrs1 = filterString(list, s -> s.contains("京"));
    System.out.println(filterStrs1);
}

//根据给定的规则,过滤集合中的字符串。此规则由Predicate的方法决定
public List<String> filterString(List<String> list, Predicate<String> pre) {

    ArrayList<String> filterList = new ArrayList<>();

    for (String s : list) {
        if (pre.test(s)) {
            filterList.add(s);
        }
    }

    return filterList;

}

image-20200923194305931

其他接口

函数式接口参数类型返回类型用途
BiFunction<T, U, R>T, UR对类型为 T, U 参数应用操作,返回 R 类型的结 果。包含方法为: R apply(T t, U u);
UnaryOperator (Function子接口)TT对类型为T的对象进行一元运算,并返回T类型的 结果。包含方法为:T apply(T t);
BinaryOperator (BiFunction 子接口)T, TT对类型为T的对象进行二元运算,并返回T类型的 结果。包含方法为: T apply(T t1, T t2);
BiConsumer<T, U>T, Uvoid对类型为T, U 参数应用操作。 包含方法为: void accept(T t, U u)
BiPredicate<T,U>T,Uboolean包含方法为: boolean test(T t,U u)
ToIntFunction< T > ToLongFunction< T > ToDoubleFunction< T >Tint long double分别计算int、long、double值的函数
IntFunction< R > LongFunction< R > DoubleFunction< R >int long doubleR参数分别为int、long、double 类型的函数

image-20200923194851914

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值