Java 8 函数式接口

定义:

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

作用:

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

注解 : 

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

内置函数接口:

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

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

抽象方法:

        void accept(T t):接收一个参数进行消费,但无需返回结果。

默认方法:

       为了下面能更好地解释,这里先假设有两个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():返回一个自定义数据

例子:

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实例: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实例: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值。

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

 

 

  • 14
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: Java 8 函数式接口是一种拥有单个抽象方法的接口,它可以被隐式地转换为 lambda 表达式。您可以使用 @FunctionalInterface 注解声明一个接口为函数式接口。这样做可以帮助编译器检测到您是否正确地在接口中声明了单个抽象方法。 例如: ``` @FunctionalInterface public interface Converter<F, T> { T convert(F from); } ``` 这是一个函数式接口,因为它只有一个抽象方法 `convert()`。您可以使用 lambda 表达式来实现这个接口: ``` Converter<String, Integer> converter = (from) -> Integer.valueOf(from); Integer converted = converter.convert("123"); System.out.println(converted); // 123 ``` 函数式接口使用起来非常方便,因为它们可以被隐式地转换为 lambda 表达式。这使得您可以使用更简洁的代码来实现接口,而无需显式地创建一个类来实现该接口。 ### 回答2: Java 8引入了函数式接口,这是一种只有一个抽象方法的接口。函数式接口提供了一种简洁的方式来定义Lambda表达式,Lambda表达式可以作为函数的参数使用。 函数式接口可以通过使用@FunctionalInterface注解来明确标识。这个注解是可选的,但建议使用,因为它可以确保接口只有一个抽象方法,防止不必要的错误。 Java 8提供了一些内置函数式接口,用于处理常见的函数式编程场景。其中一些常用的函数式接口包括: 1. Predicate(断言):代表一个谓词(布尔类型函数),接受一个参数,返回一个布尔值结果。 2. Consumer(消费者):代表一个消费者(接受一个参数并执行某些操作),接受一个参数,不返回任何结果。 3. Function(函数):代表一个函数(接受一个参数并返回一个结果),接受一个参数并返回一个指定类型的结果。 4. Supplier(供应者):代表一个供应者(不接受参数但返回一个结果),不接受任何参数,返回一个指定类型的结果。 这些函数式接口的引入使得Java 8具备了更强大的函数式编程能力,使代码更加简洁和易读。通过结合Lambda表达式和函数式接口,我们可以实现与函数式编程语言类似的编程风格,提高代码的可读性和可维护性。 ### 回答3: Java 8 引入了函数式接口的概念。函数式接口是一个只有一个抽象方法的接口。在 Java 8 之前,我们需要定义一个接口,并在其中添加一个抽象方法,才能够当作 Lambda 表达式的参数进行传递。而在 Java 8 中,我们只需使用 @FunctionalInterface 注解来标注一个接口,就可以将其定义为函数式接口了。这使得我们能够更加简洁地使用 Lambda 表达式。 函数式接口可以用来支持函数式编程,也可以用作 Lambda 表达式的类型。而 Java 8 为我们提供了一些内置函数式接口,如 Function、Predicate、Consumer、Supplier 等。这些接口都定义了一些常用的函数式方法,例如 Function 接口中的 apply() 方法,Predicate 接口中的 test() 方法。这些方法可以直接在 Lambda 表达式中使用。 通过使用函数式接口,我们可以更加方便地使用 Lambda 表达式来完成一些常见的操作。例如,我们可以使用 Predicate 接口来过滤集合中的元素,使用 Function 接口来对集合元素进行转换,使用 Consumer 接口来消费集合元素,使用 Supplier 接口来生产对象等等。 总之,Java 8 的函数式接口为我们提供了更加便捷的函数式编程方式。我们可以利用这些接口来定义、传递和使用 Lambda 表达式,从而简化代码,提高开发效率。同时,函数式接口也使得代码更加易读和易维护。然而,我们需要注意函数式接口的设计和使用,以避免出现意外的错误。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值