jdk8 接口新特性、函数接口

400 阅读3分钟

这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战

jdk8接口新特性

上一次写到 :juejin.cn/post/699927… 用lambda表达式写了一个接口,并写了4个示例

interface Interface1{
    int doubleNum(int i);
}

public static void main(String[] args) {
    Interface1 i1 = (i) ->i * 2;

    //最常见写法
    Interface1 i2 = i->i*2;

    Interface1 i3 = (int i)->i*2;

    Interface1 i4= (int i)->{
        System.out.println("----");
        return i*2;
    };
}

那么我们队接口有么有什么限制呢,就是接口里面有且只有一个要实现的方法(doubleNum)

这是java8新引入的 概念叫:函数接口 @FunctionalInterface

如果加了注解之后继续写实现的话,就会报错

image.png

进入jdk8之后,我们需要将接口设计的小,这就是单一责任制。 我们实际设计接口的时候,也要尽量设计的细一点,尽量每个接口只做一个事,而且接口可以多继承,我们可以最后写一个类,一个接口来继承这些接口,更细的接口可以让我们用lambda更方便

所以 @FunctionalInterface 还是要尽量加一下

lambda 表达式要实现的接口仅有一个,不代表里面的实现只有一个, 虽然

int doubleNum(int i);
int doubleNum2(int i2);

是报错的 但是默认实现的是不管的

image.png

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

    default int add(int x,int y){
        return x+y;
    }
}

public static void main(String[] args) {
    Interface1 i1 = (i) ->i * 2;

    i1.add(5,5);
    System.out.println(i1.doubleNum(20));
}

image.png

接口多重继承方法,default方法覆盖的场景 首先我们复制Interface1 为 Interface2

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

    default int add(int x,int y){
        return x+y;
    }
}

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

    default int add(int x,int y){
        return x+y;
    }
}

然后 Interface3 同时继承 前面2个接口

image.png

发现程序无法知道我们要默认实现 Interface2 还是 Interface1 ,是add 还是 doubleNum

我们执行 Interface2的 add接口

@FunctionalInterface
interface Interface3 extends Interface2,Interface1{

    @Override
    default int add(int x, int y) {
        return Interface1.super.add(x, y);
    }
}

得到以上结果

jdk8的函数接口,这些接口好用还好学

写一个印钱程序

使用函数式接口之前

interface IMoneyFormat{
    String format(int i);
}

class MyMoney{
    private final int money;

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

    public void printMoney(IMoneyFormat moneyFormat){
        System.out.println("我的存款"+ moneyFormat.format(this.money));
    }
}

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

        me.printMoney(i -> new DecimalFormat("#,###").format(i));

    }
}

但是函数式接口并不关注你实现的接口,也就是说他不需要知道你的名字,也不需要知道你的方法只需要知道输入是什么,输出是什么

那我们就没必要总写接口,只要给一个输入是int类型 输出是String类型的函数Function<Integer,String>就OK 了 。

class MyMoney{
    private final int money;

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

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

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

        me.printMoney(i -> new DecimalFormat("#,###").format(i));

    }
}

可以看出函数接口的好处就是不定义太多接口

第二个好处就是函数接口支持链式操作

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

        Function<Integer,String> moneyFormat = i->new DecimalFormat("#,###").format(i);
       //函数接口链式操作
        me.printMoney(moneyFormat.andThen(s->"rmb"+s));

    }
}

image.png

有输入无输出为 提供者,有输出无输入为消费者

演示

import java.util.function.Consumer;
import java.util.function.IntPredicate;
import java.util.function.Predicate;

public class FunctionDemo {
    public static void main(String[] args) {
        IntPredicate predicate = i->i>0;
        //断言
        System.out.println(predicate.test(-9));

        //消费
        Consumer<String> consumer = s -> System.out.println(s);
        consumer.accept("输入的数据");

    }
}