1. 函数式接口

1.1. 接口允许有默认实现

@FunctionalInterface
interface TestInterface {
    // 要实现的方法
    int doubleNum(int i);

    // 默认实现方法
    default int add(int x, int y) {
        return x + y;
    }
}

public static void main(String[] args) {
    // lambda 表达式实现doubleNum方法并返回该接口的实例对象
    TestInterface interface1 = i -> i * 2;

    // 调用接口的doubleNum方法和add方法
    System.out.println(interface1.doubleNum(1));
    System.out.println(interface1.add(1,2));
}

小结 值得说明的是,默认接口实现应该是对所有的实现类来说有价值的默认实现,接口是对行为的规范,对接口的定义必须相当谨慎.那我们熟悉的 List 来说,查询源码,搜索@since发现,大多 api 是1.2,1.3,1.4...竟然没有,而1.8新增的也是 default 接口,为什么? 因为增加接口就需要实现,所以轻易不会新增接口,但是 jdk8允许有默认接口实现,这就解决了需要重新实现接口方法的问题,这也是为什么我们认为这是 jdk8的重大更新; 这里需要说明下 jdk8新增了默认接口实现方法,我们称之为默认接口实现方法,而 lambda 表达式实现的接口方法,我们称之为默认方法吧;

默认接口实现方法可以认为是内部实现类,也可以使用 this;

@FunctionalInterface
interface Interface1 {
    int doubleNum(int i);

    default int add(int x, int y) {
        System.out.println(this.doubleNum(1));
        return x + y;
    }
}

public static void main(String[] args) {
    Interface1 interface1 = i -> i * 2;
    System.out.println(interface1.add(1, 2));
}

接口多继承时,需要指明具体覆盖哪一个默认实现方法

@FunctionalInterface
interface Interface1 {
    int doubleNum(int i);

    default int add(int x, int y) {
        System.out.println("Interface1 add");
        return x + y;
    }
}

@FunctionalInterface
interface Interface2 {
    int doubleNum(int i);

    default int add(int x, int y) {
        System.out.println("Interface2 add");
        return x + y;
    }
}

@FunctionalInterface
interface Interface3 extends Interface2, Interface1 {

    @Override
    default int add(int x, int y) {
        System.out.println("Interface3 add");
        return Interface1.super.add(x, y);
    }
}

public static void main(String[] args) {
    Interface3 interface3 = i -> i * 2;
    System.out.println(interface3.add(1, 2));
}

接口真的需要吗,有没有更简洁的方法

public class MyMoneyDemo {

    public static void main(String[] args) {
        MyMoney myMoney = new MyMoney(9999999);
        myMoney.printMoney(i -> new DecimalFormat("#,###").format(i));
    }
}

interface IMoneyFormat {
    String format(int money);
}

class MyMoney {
    private final int money;

    public MyMoney(int money) {
        this.money = money;
    }

    public void printMoney(IMoneyFormat moneyFormat) {
        System.out.println("MyMoney is " + moneyFormat.format(this.money));
    }
}

以上例子,定义一个接口,然后 lambda 表达式生成接口的实现类,从而实现接口功能; 其实不难发现,lambda 表达式实现的过程中,我们并不关心接口的参数以及方法名,我们仅仅关心入参和出参,那让我们进一步简化吧;

public class MyMoneyDemo {

    public static void main(String[] args) {
        MyMoney myMoney = new MyMoney(9999999);
        myMoney.printMoney(i -> new DecimalFormat("#,###").format(i));
    }
}

class MyMoney {
    private final int money;

    public MyMoney(int money) {
        this.money = money;
    }

    public void printMoney(Function<Integer,String> moneyFormat) {
        System.out.println("MyMoney is " + moneyFormat.apply(this.money));
    }
}

这就是函数式编程,不必定义那么多接口,此外函数式接口还支持链式操作;

public class MyMoneyDemo {

    public static void main(String[] args) {
        MyMoney myMoney = new MyMoney(9999999);

        Function<Integer, String> moneyFormat = i -> new DecimalFormat("#,###").format(i);
        myMoney.printMoney(moneyFormat.andThen(s -> "RMB: " + s));
    }
}

class MyMoney {
    private final int money;

    public MyMoney(int money) {
        this.money = money;
    }

    public void printMoney(Function<Integer, String> moneyFormat) {
        System.out.println("MyMoney is " + moneyFormat.apply(this.money));
    }
}

小结

接口 输入参数 返回类型 说明
Predicate T boolean 断言
Consumer T / 消费一个数据
Function T R 输入T输出R的函数
Supplier / R 提供一个数据
UnaryOperator T T 一元函数(输出输入类型相同)
BiFunction R 两个输入的函数
BinaryOperator T 两元函数(输出输入类型相同)
作者: 雪之梦技术驿站
链接: https://snowdreams1006.github.io/java8/functionInterface.html
来源: 雪之梦技术驿站
本文原创发布于「雪之梦技术驿站」,转载请注明出处,谢谢合作!

https://snowdreams1006.github.io/snowdreams1006-wechat-open.png

© snowdreams1006 all right reserved,powered by Gitbook文件修订时间: 2019-11-01 19:34:36

results matching ""

    No results matching ""