Java8函数式接口

Java8自带的函数式接口

函数接口 抽象方法 功能 参数 返回值类型 示例
Predicate test(T t) 判断真假 T Boolean 小明的身高大于185CM吗
Consumer accept(T t) 消费消息 T void 输出一个值
Function R apply(T t) 将T映射为R(转换功能) T R 获得Student对象的名称
Supplier T get() 生成消息 T 工厂方法
UnaryOperator T apply(T t) 一元操作 T T 逻辑非
BinaryOperator apply(T t,U u) 二元操作 (T,T) (T) 求两个数的乘机

编程实现

  1. /**
  2. * 测试Lambda函数接口
  3. *
  4. * @author zukxu
  5. * CreteTime 2021/7/17 0017 00:18
  6. */
  7. public class TestLambda {
  8. public static void main(String[] args) {
  9. Student student = new Student().setName("小明").setAge(23).setHeight(180);
  10. // 判断真假 Predicate
  11. Predicate<Integer> pred = x -> x > 185;
  12. System.out.println(pred.test(student.getHeight()));
  13. // 消费消息
  14. Consumer<String> consumer = System.out::println;
  15. consumer.accept("我命由我不由天");
  16. // 转换功能
  17. Function<Student, String> function = Student::getName;
  18. String name = function.apply(student);
  19. System.out.println(name);
  20. // 生产消息
  21. Supplier<Integer> supplier = () -> Integer.valueOf(BigDecimal.TEN.toString());
  22. System.out.println(supplier.get());
  23. // 一元操作
  24. UnaryOperator<Boolean> unaryOperator = u -> !u;
  25. Boolean apply = unaryOperator.apply(false);
  26. System.out.println(apply);
  27. // 二元操作
  28. BinaryOperator<Integer> binaryOperator = (x, y) -> x * y + 2;
  29. Integer binary = binaryOperator.apply(5, 15);
  30. System.out.println(binary);
  31. }
  32. }

【 Student::getName;】这种操作被称之为方法引用

自定义函数式接口

  1. /**
  2. * 测试自定义lambda函数式接口
  3. *
  4. * @author zukxu
  5. * CreteTime 2021/7/17 0017 00:34
  6. */
  7. public class TestCustomFunc {
  8. public static void main(String[] args) {
  9. testCustom(() -> "我是一个自定义函数式接口");
  10. }
  11. public static void testCustom(Worker worker) {
  12. System.out.println(worker.work());
  13. }
  14. public interface Worker {
  15. String work();
  16. }
  17. }

一、why?

函数式编程更多时候是一种编程的思维方式,是种方法论。函数式与命令式编程的区别主要在于:函数式编程是告诉代码你要做什么,而命令式编程则是告诉代码要怎么做。说白了,函数式编程是基于某种语法或调用API去进行编程。
例如:

命令式编程

  1. public static void main(String[] args) {
  2. int[] nums = new int[]{1, 2, 3, 4, 5, 6, 7, 8};
  3. int min = Integer.MAX_VALUE;
  4. for (int num : nums) {
  5. if (num < min) {
  6. min = num;
  7. }
  8. }
  9. System.out.println(min);
  10. }

函数式编程:

  1. public static void main(String[] args) {
  2. int[] nums = new int[]{1, 2, 3, 4, 5, 6, 7, 8};
  3. int min = IntStream.of(nums).min().getAsInt();
  4. System.out.println(min);
  5. }

二、lambda函数式接口

1.函数接口

接口只能有一个需要实现的方法,可以使用@FunctionalInterface 注解进行声明。如下:

  1. @FunctionalInterface
  2. interface Interface1 {
  3. int doubleNum(int i);
  4. }

使用lambda表达式进行获取相关实现实例:

  1. public static void main(String[] args) {
  2. // 最常见的写法
  3. Interface1 i1 = (i) -> i * 2;
  4. Interface1 i2 = i -> i * 2;
  5. // 可以指定参数类型
  6. Interface1 i3 = (int i) -> i * 2;
  7. // 若有多行代码可以这么写
  8. Interface1 i4 = (int i) -> {
  9. System.out.println(i);
  10. return i * 2;
  11. };
  12. }

2.默认方法

比较重要的一个接口特性是接口的默认方法,用于提供默认实现。默认方法和普通实现类的方法一样,可以使用this等关键字

  1. @FunctionalInterface
  2. interface Interface1 {
  3. int doubleNum(int i);
  4. default int add(int x, int y) {
  5. return x + y;
  6. }
  7. }

之所以说默认方法这个特性比较重要,是因为我们借助这个特性可以在以前所编写的一些接口上提供默认实现,并且不会影响任何的实现类以及既有的代码。例如我们最熟悉的List接口,在JDK1.2以来List接口就没有改动过任何代码,到了1.8之后才使用这个新特性增加了一些默认实现。这是因为如果没有默认方法的特性的话,修改接口代码带来的影响是巨大的,而有了默认方法后,增加默认实现可以不影响任何的代码。

3.当接口多重继承时

当接口多重继承时,可能会发生默认方法覆盖的问题,这时可以去指定使用哪一个接口的默认方法实现,如下示例:

  1. @FunctionalInterface
  2. interface Interface1 {
  3. int doubleNum(int i);
  4. default int add(int x, int y) {
  5. return x + y;
  6. }
  7. }
  8. @FunctionalInterface
  9. interface Interface2 {
  10. int doubleNum(int i);
  11. default int add(int x, int y) {
  12. return x + y;
  13. }
  14. }
  15. @FunctionalInterface
  16. interface Interface3 extends Interface1, Interface2 {
  17. @Override
  18. default int add(int x, int y) {
  19. // 指定使用哪一个接口的默认方法实现
  20. return Interface1.super.add(x, y);
  21. }
  22. }

三、惰性求值与及早求值

  • 惰性求值:只描述Stream,操作的结果也是Stream,这样的操作称为惰性求值。惰性求值可以像建造者模式一样链式使用,最后再使用及早求值得到最终结果
  • 及早求值:得到最终的结果而不是Stream,这样的操作称为及早求值。

    附录: