Java8函数式接口编程【lambda表达式、FunctionalInterface注解、Supplier、Consumer、Predicate、Function函数式接口】


1、函数式接口的定义

有且仅有一个抽象方法的接口

函数式接口顾名思义就是函数式编程的接口,在Java中最能体现函数式编程的无非就是Lambda,所以函数式接口是可以适用于Lambda使用的接口;

只有确保只有一个抽象方法,Lambda才能顺利地推导

2、FunctionalInterface注解

该注解与Override注解类似,FunctionalInterface用来检测该接口是否是一个函数式接口(只有一个抽象方法)

被@FunctionalInterface注解标记的类型表明这是一个函数接口。从概念上讲,函数接口只有一个抽象方法。如果接口声明的抽象方法覆写Object类的公共方法,那这方法不算作接口的抽象方法,因为接口具有Object方法的默认实现。

3、函数式接口的使用

首先定义一个函数式接口

@FunctionalInterface
public interface MyFunctionInterface {
    public abstract void method();
}

(1)第一种使用方式(实现接口)

重写接口
在testFun方法参数中定义接口
调用时传入它的实现类

public class MyFunctionInterfaceImpl implements MyFunctionInterface{
    @Override
    public void method() {
        System.out.println("第一种函数式接口的使用方式...");
    }
}
public class TestFunctionInterface {

    public static void testFun(MyFunctionInterface myFunctionInterface) {
        myFunctionInterface.method();
    }
    public static void main(String[] args) {
        testFun(new MyFunctionInterfaceImpl());
    }
}

(2)内名内部类

testFun(new MyFunctionInterface() {
            @Override
            public void method() {
                System.out.println("第二种实现方式...");
            }
        });

(3)Lambda表达式

		testFun(()->{
            System.out.println("第三种实现方式");
        });
        或者
        testFun(()-> System.out.println("第三种实现方式"));

4、lambda延迟执行特性

使用一个日志案例来演示

public class lambdaLater {

    public static void log(int k, String msg) {
        if (k == 1) {
            System.out.println(msg);
        }
    }

    public static void main(String[] args) {
        String msg1 = "aa";
        String msg2 = "bb";
        String msg3 = "cc";

        log(2, msg1 + msg2 + msg3);
    }
}

根据上文代码,如果传入的k=2,那么日志不会打印,但是msg1 + msg2 + msg3已经完成了拼接,这样就会浪费性能。

❤️ 经过lambda优化

使用lambda之前,首先需要定义一个函数式接口。

@FunctionalInterface
public interface LambdaLaterInterface {
    public abstract String printMsg();
}

测试

public class lambdaLater {

    public static void log2(int k, LambdaLaterInterface lambdaLaterInterface) {
        if (k == 1) {
            System.out.println(lambdaLaterInterface.printMsg());
        }
    }

    public static void main(String[] args) {
        String msg1 = "aa";
        String msg2 = "bb";
        String msg3 = "cc";

        log2(2, () -> {
            System.out.println("------");
            return msg1 + msg2 + msg3;
        });
    }
}

结果如下

没有“-------”,说明字符串没有进行拼接。
在这里插入图片描述


5、Supplier函数式接口

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

根据Supplier源代码可以看出,Supplier接口中是一个无参的的抽象方法;当你接口泛型指定什么类型,那么T get()抽象方法就会返回什么类型。

所以Supplier被成为生产型接口

public class SupplierDemo {

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

    public static void main(String[] args) {
    //只有一行代码,省略了return和{}和,
        String s = sup(() -> "hello");
        System.out.println(s);
    }
}
public class SupplierDemo {

    public static int getMax(Supplier<Integer> sup) {
        return sup.get();
    }
    public static void main(String[] args) {
        int[] nums = {1, 3, 5, 0, 9};
        int maxNum = getMax(() -> {
            int max = nums[0];
            for (int temp : nums) {
                if (temp > max)
                    max = temp;
            }
            return max;
        });
        System.out.println(maxNum);
    }
}

6、Consumer函数式接口

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

这个Consumer接口刚好和Supplier接口的作用相反,如果接口泛型定义了什么类型,那么方法accept就可以消费什么类型;

Consumer是一个典型的消费型接口

public class ConsumerDemo {
    public static void strRev(String str, Consumer<String> con) {
        con.accept(str);
    }
    public static void main(String[] args) {
        strRev("test", (temp) -> {
            String result = new StringBuilder(temp).reverse().toString(); //反转字符串
            System.out.println(result);
        });
    }
}

在Consumer接口中,有一个默认的方法andThen

这个andThen方法的作用是对两个Consumer接口进行连接消费

 default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
public class ConsumerDemo {
   
    public static void strRev(String str, Consumer<String> consumer, Consumer<String> consumer2) {
        consumer.andThen(consumer2).accept(str);
    }
        //进行组合消费
        strRev("hello",
                (name) -> {
                    System.out.println(name.toLowerCase());
                },
                (name2) -> {
                    System.out.println(name2.toUpperCase());
                });
    }
}

7、Predicate函数式接口

源代码中包含了一个抽象方法test和四个默认方法

@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);  //抽象方法
	//逻辑与
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
	//逻辑否
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }
	//逻辑或
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

	//比较两个对象是否相等
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}
public class PredicateDemo {

    public static boolean predicate(int a, Predicate<Integer> predicate) {
        return predicate.test(a);
    }
    public static void main(String[] args) {

        boolean flag = predicate(6, (num) -> {
            return num > 5;
        });
        System.out.println(flag);
    }
}

and方法的用法,与&&等同

public class PredicateDemo {

    public static boolean predicate2(int a, Predicate<Integer> pre, Predicate<Integer> pre2) {
        return pre.and(pre2).test(a);
    }

    public static void main(String[] args) {
        boolean flag2 = predicate2(6,
                (num) -> {
                    return num > 2;
                },
                (num2) -> {
                    return num2 > 8;
                });
        System.out.println(flag2);
    }  
}

or方法和and方法类似,与||等同。
negate方法,与!(取反)等同。


8、Function函数式接口

andThen方法的应用

在fun的基础上,fun2在进行加20,结果等于42;

    public static Integer function2(String s, Function<String, Integer> fun, Function<Integer,Integer> fun2) {
        return fun.andThen(fun2).apply(s);
    }
    public static void main(String[] args) {
        Integer a = function2("12", (num) -> {
            return Integer.valueOf(num) + 10;
        }, (num)->{
            return num + 20;
        });
        System.out.println(a);
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thecoastlines

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值