一页书

你永远不会过度准备

函数式接口

什么是函数式接口

Lambda的设计者们为了让现有的功能与Lambda表达式良好兼容,考虑了很多方法,于是产生了 函数接口 这个概念。

函数式接口在Java中是指:有且仅有一个抽象方法的接口。

因此在实践中,函数式接口非常脆弱:只要某个开发者在该接口中添加一个函数,则该接口就不再是函数式接口进而导致编译失败。

为了克服这种代码层面的脆弱性,并显式说明某个接口是函数式接口,Java 8 提供了一个特殊的注解 @FunctionalInterface(Java 库中的所有函数式接口都已经带有这个注解了)

@FunctionalInterface

这是Java 8中专门为函数式接口引入的一个新注解;与 @Override 注解的作用类似,起表示作用,用于代码检查;
该注解可用于一个接口的定义上:表示这是一个函数式接口。
比如:

@FunctionalInterface
public interface Functional { 
    void method();
}

即使不使用该注解,只要满足函数式接口的定义,这仍然是一个函数式接口,使用起来都一样。

不过有一点需要注意,默认方法和静态方法 不会破坏函数式接口的定义,因此如下的代码是合法的。

@FunctionalInterface
public interface FunctionalDefaultMethods {
  void method();
  default void defaultMethod() {
    System.out.println("我是默认方法");
  }
  static void staticMethod(){
    System.out.println("我是静态方法");
  }
}

常用内置函数式接口

我们知道使用Lambda表达式的前提是需要有函数式接口。

而Lambda使用时不关心接口名,抽象方法名,只关心抽象方法的参数列表和返回值类型

因此为了让我们使用Lambda方便,JDK提供了大量常用的函数式接口。

它们主要在 java.util.function 包中。下面是最常用的几个接口。

  1. Supplier 接口;供给型接口,通过 Supplier 接口中的 get 方法可以得到一个值,无参有返回的接口。
@FunctionalInterface
public interface Supplier<T> {
    public abstract T get();
}

Supplier使用示例

//返回数组元素最大值
public class DemoSupplier {
    public static void main(String[] args) {
        printMax(() -> {
            int[] arr = {10, 20, 100, 30, 40, 50};
            // 先排序,最后就是最大的
            Arrays.sort(arr);
            return arr[arr.length - 1]; // 最后就是最大的
        });
    }
    private static void printMax(Supplier<Integer> supplier) {
        int max = supplier.get();
        System.out.println("max = " + max);
    }
}
  1. Consumer 接口;消费型接口,通过 Consumer 接口中的 accept 方法可以消费一个数据,有参无返回接口。
@FunctionalInterface
public interface Consumer<T> {
    public abstract void accept(T t);
}

Consumer使用示例

//将一个字符串转成大写和小写的字符串
public class DemoConsumer {
    public static void main(String[] args) {
        // Lambda表达式
        test((String s) -> {
            System.out.println(s.toLowerCase());
        });
    }
    public static void test(Consumer<String> consumer) {
        consumer.accept("HelloWorld");
    }
}
  1. Function 接口;用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。有参数有返回值。
@FunctionalInterface
public interface Function<T, R> {
    public abstract R apply(T t);
}

Function使用示例

//使用Lambda表达式将字符串转成数字
public class DemoFunction {
    public static void main(String[] args) {
        // Lambda表达式
        test((String s) -> {
            return Integer.parseInt(s); // 10
        });
    }
    public static void test(Function<String, Integer> function) {
        Integer in = function.apply("10");
        System.out.println("in: " + (in + 5));
    }
}
  1. Predicate 接口;常用于做判断,有参数,返回boolean类型的值
@FunctionalInterface
public interface Predicate<T> {
    public abstract boolean test(T t);
}

Predicate使用示例

//使用Lambda判断一个人名如果超过3个字就认为是很长的名字
public class DemoPredicate {
    public static void main(String[] args) {
        test(s -> s.length() > 3, "迪丽热巴");
    }
    private static void test(Predicate<String> predicate, String str) {
        boolean veryLong = predicate.test(str);
        System.out.println("名字很长吗:" + veryLong);
    }
}
0%