飞道的博客

Java8 -- 02 -- 函数式接口

579人阅读  评论(0)

函数式接口,是指只定义了一个抽象方法的接口,它可以拥有多个非抽象方法,同时可以被隐式转换为 lambda 表达式


一、函数式接口

  • 在 Java8 中,接口可以拥有默认方法 (即在类没有对方法进行实现时,其主体为方法提供默认实现的方法),哪怕有很多默认方法,只要一个接口只定义了一个抽象方法,它就仍然是一个函数式接口,此外我们将函数式接口的抽象方法的签名称为函数描述符

    • 举例说明

      // 下面哪些接口是函数式接口
      public interface Adder {
          int add(int a, int b);
      }
      
      public interface SmartAdder extends Adder {
          int add(int a, int b);
      }
      
      public interface Nothing {
          
      }
      
      • 只有 Adder 是函数式接口

      • SmartAdder 定义了两个叫做 add 的抽象方法,一个是其自身定义的,还有一个是从 Adder 继承得到的

      • Nothing 中没有定义抽象方法

  • 在阅读源码的时候,我们会发现,函数式接口都会带有 @FunctionInterface 注解,该注解的主要作用是:强制规定当前接口为函数式接口,如果接口中存在两个及以上抽象方法,就会编译报错


二、函数式接口的使用

  • 在 java.util.function 包下存在很多函数式接口,用于支持函数式编程,这里主要介绍下 Java8 核心的四大接口:Predicate、Consumer、Function、Supplier

  • Predicate (断言型接口)

    • Predicate<T> 接口中定义了一个名为 test 的抽象方法,它接收一个泛型 T 对象,并返回一个 boolean

    • 举例说明

      List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
      Predicate<Integer> predicate = i -> i % 2 == 0;
      List<Integer> evenList = list.stream().filter(predicate).collect(toList());
      System.out.println(evenList); // [2, 4, 6, 8]
      
      • filter 方法接收 predicate 对象作为参数,用于筛选偶数
  • Consumer (消费型接口)

    • Consumer<T> 接口中定义了一个名为 accept 的抽象方法,它接收一个泛型 T 对象,没有返回 (void)

    • 举例说明

      List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
      Consumer<Integer> consumer = System.out::print;
      list.forEach(consumer); // 123456789
      
      • forEach 方法接收 consumer 对象作为参数,用于循环遍历
  • Function (函数型接口)

    • Function<T, R> 接口中定义了一个名为 apply 的抽象方法,它接收一个泛型 T 对象,并返回一个泛型 R 对象

    • 举例说明

      Function<Integer, Integer> function = i -> i * 2;
      List<Integer> strList = list.stream().map(function).collect(toList());
      System.out.println(strList); // [2, 4, 6, 8, 10, 12, 14, 16, 18]
      
      • map 方法接收 function 对象作为参数,用于将数值翻倍
  • Supplier (供给型接口)

    • Supplier<T> 接口中定义了一个名为 get 的抽象方法,它不接收参数,返回一个泛型 T 对象

      Supplier<String> supplier = () -> "HelloWorld";
      System.out.println(supplier.get()); // HelloWorld
      
      • supplier 对象调用 get() 方法为输出提供内容

三、避免自动装箱

  • 我们先来看下以下代码,是可以正确运行的,这是因为 Java 会将基本数据类型自动转换为其对应的引用类型

    • 装箱:将基本数据类型转换为其对应的引用类型

    • 拆箱:将引用类型转换为其对应的基本数据类型

      List<Integer> list = new ArrayList<>();
      for (int i = 0; i < 10; i++) {
          list.add(i);
      }
      System.out.println(list); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      
  • 在 Java8 中,定义了专门的函数式接口,以便在输入和输出都是基本数据类型的时候避免自动装箱

    • 举例说明 (IntPredicate)

      public interface IntPredicate {
      
          boolean test(int value);
      }
      
      // 无装箱
      IntPredicate intPredicate = (int i) -> i % 2 == 0;
      intPredicate.test(100); // true
      
      // 有装箱
      Predicate<Integer> predicate = (Integer i) -> i % 2 == 0;
      predicate.test(100); // true
      
      • 在这里,使用 IntPredicate 就避免了对值 100 进行装箱操作
    • 类似的还有 IntConsumer、IntFunction、LongConsumer、LongFunction、LongPredicate 等接口


转载:https://blog.csdn.net/Goodbye_Youth/article/details/106857165
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场