定义:

只能有一个抽象方法
可以有静态方法和默认方法,因为这两种方法都是已经实现的了
可以包含Object里所有能重写的方法,因为即使接口包含像String toString()这样的抽象方法,它的实现类也会因继承了Object类,而再次对接口中的toString()方法进行实现。 
作用:

方便直接用Lambda表达式构造出实例,让代码更加简洁。

Lambda表达式必须先定义接口,创建相关方法后才能使用,这样弄十分不便,干脆开发者就直接内置了接口,所有标注@FunctionalInterface注解的接口都是函数式接口

jdk8内置的四大核心函数式接口

接口类型

参数情况

定义的抽象方法

Consumer:消费型接口

有入参,无返回值

void accept(T t);

Supplier:供给型接口

无入参,有返回值

T get();

Function<T,R>:函数型接口

有入参,有返回值

R apply(T t);

Predicate:断言型接口

有入参,有返回值,返回值类型确定是boolean

boolean test(T,t);

    

注解 :

 
@FunctionalInterface与@Override注解作用相似,用于在编译期间检查接口是否符合函数式接口的语法。

内置函数接口:

为了减少函数式接口的编写,JDK已经帮我们抽出几种常用的函数式接口:

1. 消费型接口 Consumer<T> :

抽象方法:

void accept(T t):接收一个参数进行消费,但无需返回结果。
 Consumer<T> 有入参,无返回值。idea中可以通过ctrl+shift+n输入Consumer.java找到源代码。

 主要的应用场景打印日志,发送短信

默认方法:

       为了下面能更好地解释,这里先假设有两个Consumer实例:c1,22

default Consumer<T> andThen(Consumer<? super T> after):c1.andThen(c2).apply(arg),c1消费完arg后,再将arg传给c2消费。

例子:

public class ConsumerDemo {
  
     @Test
     public void cutHand() {
         Goods goods = new Goods("口红", 288);
  
         //土豪
         spentMoney(goods, (g) -> System.out.println("消费" + g.getCost() + "元"));
  
         System.out.println("-------------------贫富分割线--------------------");
  
         //屌丝
         spentMoneyAndLog(goods, (g) -> System.out.println("消费" + g.getCost() + "元"));
     }
     
     //任性地花
     public void spentMoney(Goods goods, Consumer<Goods> consumer) {
         consumer.accept(goods);
     }
  
     //花一笔记一笔
     public void spentMoneyAndLog(Goods goods, Consumer<Goods> consumer) {
         Consumer<Goods> logConsumer = (g) -> System.out.println("买" + g.getGoodsName() + "用了" + g.getCost() + "元!");
         consumer.andThen(logConsumer).accept(goods);
     }
 }
  
 运行结果:
 消费288.0元
 -------------------贫富分割线--------------------
 消费288.0元
 买口红用了288.0元!

2. 供给型接口 Supplier<T> :

抽象方法:

        T get():返回一个自定义数据

Supplier是供给型接口,无入参,有返回值 。也就是没有入参。

运用场景:如果项目中你需要一些实体类需要有默认值,而有些地方不需要默认值,我们如何处理呢?我们可以设计一个工厂模式,工厂对实体类生产两种产品,一个有默认值,一个没有默认值。

 例子:

public class SupplierDemo {
     @Test
     public void luckDay() {
         Supplier<String> girlWish = () -> "美女";
         Supplier<String> moneyWish = () -> "钱";
  
         String girl = magicLamp(girlWish);
         String money = magicLamp(moneyWish);
  
         System.out.println(girl + "---" + money);
     }
  
     //你想要什么神灯就给你什么
     public String magicLamp(Supplier<String> wish) {
         return wish.get();
     }
 }
  
 运行结果:
 美女---钱

3. 函数型接口 Function<T,R> :

抽象方法:

        R apply(T t):传入一个参数,返回想要的结果。 

Function:函数型接口,有入参,有返回值,

用途:用于执行特定的函数操作。

默认方法:

       为了下面能更好地解释,这里先假设有两个Function实例:f1,f2

default <V> Function<V, R> compose(Function<? super V, ? extends T> before):f1.compose(f2).apply(arg),表示先执行f2,然后将得到的结果传给f1执行。
       default <V> Function<T,V> andThen(Function<? super R,? extends V> after):f1.andThen(f2).apply(arg),表示先执行f1,然后将得到的结果传给f2执行。

静态方法:

static <T> Function<T, T> identity():获取到一个输入参数和返回结果一样的Function实例

例子:

public class FunctionDemo {
  
     @Test
     public void life() {
         //第一次,妈妈给小明10元去买酱油
         double tips = firstBuy(10, (m) -> 10 - getSoy().getCost());
         System.out.println("小明得到的小费:" + tips);
  
         //第二次,妈妈还是给小明10元买酱油,小明思考了一下,拒绝了
         System.out.println("小明将妈妈给的" + Function.identity().apply(10) + "元还了回去");
  
         //妈妈在了解完情况后,给了小明20元去买,小明当然很愉快去了
         double tips2 = secondBuy(20, (m) -> {
             System.out.println("买酱油前有" + m + "元");
             double v2 = m - getSoy().getCost();
             System.out.println("买完酱油后剩下" + v2 + "元");
             return v2;
         });
         System.out.println("小明剩下的小费:" + tips2);
  
     }
  
     public double firstBuy(double money, Function<Double, Double> buy) {
         return buy.apply(money);
     }
  
     public double secondBuy(double money, Function<Double, Double> buy) {
         //在去的路上小明先买了冰淇淋
         Function<Double, Double> beforeBuy = (m) -> {
             System.out.println("第一次买冰淇淋前有" + m + "元");
             double v1 = m - getIceCream().getCost();
             System.out.println("买完冰淇淋后剩下" + v1 + "元");
             return v1;
         };
  
         //回来的路上小明又买了冰淇淋
         Function<Double, Double> afterBuy = (m) -> {
             System.out.println("第二次买冰淇淋前有" + m + "元");
             double v3 = m - getIceCream().getCost();
             System.out.println("买完冰淇淋后剩下" + v3 + "元");
             return v3;
         };
  
         return buy.compose(beforeBuy).andThen(afterBuy).apply(money);
     }
  
     public Goods getSoy() {
         return new Goods("酱油", 10);
     }
  
     public Goods getIceCream() {
         return new Goods("冰淇淋", 5);
     }
 }
  
 运行结果:
 小明得到的小费:0.0
 小明将妈妈给的10元还了回去
 第一次买冰淇淋前有20.0元
 买完冰淇淋后剩下15.0元
 买酱油前有15.0元
 买完酱油后剩下5.0元
 第二次买冰淇淋前有5.0元
 买完冰淇淋后剩下0.0元
 小明剩下的小费:0.0

4. 断言型接口 Predicate<T> :

抽象方法:

        boolean test(T t):传入一个参数,返回一个布尔值

Predicate:断言型接口,有入参,有返回值,返回值类型确定是boolean.T为入参类型,出参类型为Boolean

用途:接收一个参数,用于判断是否满足一定的条件,过滤数据。

默认方法:

       为了下面能更好地解释,这里先假设有两个Predicate实例:p1,p2

default Predicate<T> negate():表示 ! p1.test()
       default Predicate<T> and(Predicate<? super T> other):p1.and(p2).test(arg),表示p1.test(arg) && p2.test(arg)
       default Predicate<T> or(Predicate<? super T> other):p1.or(f2).test(arg),表示p1.test(arg) || p2.test(arg)

静态方法:

static <T> Predicate<T> isEqual(Object targetRef):获取到一个Predicate实例p,p.test(arg) 表示targetRef 是否等于arg

例子:

public class PredicateDemo {
  
     @Test
     public void test(){
         Predicate<String> p1=(t)->t.equals("nice");
         Predicate<String> p2=(t)->t.endsWith("e");
  
         boolean result1 = p1.test("nice");
         System.out.println(result1);
  
         boolean result2 = p1.negate().test("nice");
         System.out.println(result2);
  
         boolean result3 = p1.and(p2).test("nice");
         System.out.println(result3);
  
         boolean result4 = p1.or(p2).test("good");
         System.out.println(result4);
  
         Predicate<String> p = Predicate.isEqual("当这个参数为null,使用==判断,否则使用equal方法判断");
         boolean result5 = p.test("end");
         System.out.println(result5);
     }
 }
  
 运行结果:
 true
 false
 true
 false
 false

5. 其他类似接口

UnaryOperator<T>:一元操作符,Function的子类,只是该接口的输入参数和返回结果必须是同一类型。
BiFunction<T, U, R>:比Function高级一点,可以接收两个参数,应用后也还是返回一个结果。
BiConsumer<T,U>:同样比Consumer高级一点,可以接收两个参数进行消费而不需返回结果。
BiPredicate<T,U>:同样比Predicate高级一点,可以接收两个参数,判断后也还是返回一个bool值。

总体的,可以参考网上这张图,图中绿色表示主要引入的新接口,其他接口基本上都是为了支持基本类型而添加的接口。

java 常用函数式接口 accept 用法以及实现_抽象方法