函数式接口

一、函数式接口概述

在Java 8中,函数式接口是指只包含一个抽象方法的接口。函数式接口可以使用Lambda表达式或方法引用来创建对象,从而实现函数式编程。

这类接口只定义了唯一的抽象方的接口,并且这类接口使用了@FuctionalInterface进行注解

字面意思理解: 为了表示接口就代表这个抽象方法,所以将名起为函数式接口

Java 8中提供了许多内置的函数式接口,这些接口都位于java.util.function包下,常用的函数式接口包括:

  1. 消费式Consumer<T>:表示接受一个输入参数并且不返回任何结果的操作。主要方法:void accept(T t);

  2. 功能式Function<T, R>:表示接受一个输入参数并且返回一个结果的操作。主要方法:R apply(T t);

  3. 预测Predicate<T>:表示接受一个输入参数并且返回一个布尔值的操作。主要方法:boolean test(T t);

  4. 供给/提供Supplier<T>:表示不接受任何输入参数但是返回一个结果的操作。主要方法:T get();

以下是使用函数式接口的示例:

// Consumer示例
Consumer<String> consumer = s -> System.out.println(s);
consumer.accept("hello world");

// Function示例
Function<Integer, String> function = i -> String.valueOf(i);
String str = function.apply(123);

// Predicate示例
Predicate<Integer> predicate = i -> i > 0;
boolean result = predicate.test(-5);

// Supplier示例
Supplier<Double> supplier = Math::random;
double value = supplier.get();

在上述代码中,首先使用Lambda表达式或方法引用创建了函数式接口的对象,然后调用相应的方法执行相应的操作。

满足下面任意一个条件的接口都是函数式接口:

  1. 被@FunctionInterface注释的接口,满足@FunctionInterface注释的约束。
  2. 没有被@FunctionInterface注释的接口,但是满足@FunctionInterface注释的约束

函数式接口实例的创建有三种方式:

  1. 使用lambda表达式

Lambda表达式是一种轻量级、匿名的函数,可以用于创建实现函数式接口的对象。Lambda表达式的语法格式为:(参数列表) -> 表达式或代码块。

例如,下面的代码使用Lambda表达式创建了一个Consumer接口的实例:

Consumer<String> consumer = s -> System.out.println(s);
consumer.accept("hello world");

  1. 使用方法引用
    方法引用是一种简洁的Lambda表达式的替代形式,表示对已有方法或构造函数的引用。方法引用的语法格式为:类名::方法名或实例::方法名。
如果是一个构造方法:类名::new
如果是一个静态方法:类名::方法名
如果是一个非静态方法:对象名::方法名

例如,下面的代码使用方法引用创建了一个Function接口的实例:

Function<Integer, String> function = String::valueOf;
String str = function.apply(123);

  1. 匿名类实现
    使用匿名类创建Consumer接口的实例:
Consumer<String> consumer = new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
};
consumer.accept("hello world");

二、函数式接口的使用

1. 消费式Consumer<T>

  • 源码解析
@FunctionalInterface
public interface Consumer<T> {

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

    /**
     * andThen()方法用于将两个Consumer对象串联起来,实现多个操作的
     * 连续执行。该方法的语法格式为consumer1.andThen(consumer2),
     * 其中consumer1和consumer2分别为两个Consumer对象。
     * 
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}
  • 使用示例
Consumer<String> consumer1 = s -> System.out.println("consumer1: " + s);
Consumer<String> consumer2 = s -> System.out.println("consumer2: " + s);
Consumer<String> consumer3 = consumer1.andThen(consumer2);

consumer3.accept("hello world");

2. 功能式Function<T, R>

  • 源码解析
@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     */
    R apply(T t);

    /**
     * compose()方法用于将两个Function对象串联起来,实现多个操作
     * 的连续执行,并返回一个新的Function对象。该方法的语法格式为
     * function1.compose(function2),其中function1和function2分别
     * 为两个Function对象。
     */
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    /**
     * andThen()方法与compose()方法类似,但它先执行当前Function对象
     * 的操作,再执行参数Function对象的操作,并返回一个新的
     * Function对象。该方法的语法格式为function1.andThen(function2)
     * ,其中function1和function2分别为两个Function对象。
     */
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    /**
     * identity()方法是一个静态方法,返回一个恒等函数,即输入参数和
     * 输出结果都相同的函数。该方法的语法格式为Function.identity()
     */
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}
  • 使用示例
Function<Integer, Integer> function1 = x -> x + 1;
Function<Integer, Integer> function2 = x -> x * 2;
Function<Integer, Integer> function3 = function1.compose(function2);

int result3 = function3.apply(5);
System.out.println(result3); // 输出11

Function<Integer, Integer> function4 = function1.andThen(function2);

int result4 = function4.apply(5);
System.out.println(result4); // 输出12

Function<String, String> function = Function.identity();
String str = function.apply("hello");
System.out.println(str); // 输出hello

3. 预测Predicate<T>

  • 源码解析
@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     */
    boolean test(T t);

    /**
     * and()方法用于将两个Predicate对象组合起来,并返回一个新的Predicate对象,
     * 实现多个条件的同时满足。该方法的语法格式为predicate1.and(predicate2),
     * 其中predicate1和predicate2分别为两个Predicate对象。
     */
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

    /**
     * negate()方法用于对Predicate对象进行取反操作,并返回一个新的Predicate对象。
     * 该方法的语法格式为predicate.negate(),其中predicate为原始的Predicate对象
     */
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    /**
     * or()方法与and()方法类似,但它实现多个条件的任意一个满足即可。该方法的语法格式为predicate1.or(predicate2),
     * 其中predicate1和predicate2分别为两个Predicate对象。
     */
    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);
    }
}
  • 使用示例
Predicate<String> predicate1 = s -> s.startsWith("hello");
Predicate<String> predicate2 = s -> s.endsWith("world");
Predicate<String> predicate3 = predicate1.and(predicate2);
boolean result3 = predicate3.test("hello world");
System.out.println(result3); // 输出true
Predicate<String> predicate4 = predicate1.or(predicate2);
boolean result4 = predicate4.test("hello world");
System.out.println(result4); // 输出false
Predicate<String> negatedPredicate = predicate1.negate();
boolean result = negatedPredicate.test("hello world");
System.out.println(result); // 输出false
Predicate<String> predicate = Predicate.isEqual("hello world");
boolean result1 = predicate.test("hello world");
boolean result2 = predicate.test("hello java");
System.out.println(result1); // 输出true
System.out.println(result2); // 输出false

4. 供给/提供Supplier<T>

  • 源码解析
@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     * @return a result
     */
    T get();
}
  • 使用示例
Supplier<Double> supplier = Math::random;
double value = supplier.get();

三、自定义函数式接口

在Java中,可以通过定义自己的函数式接口来实现特定的功能。自定义的函数式接口需要满足以下要求:

  • 只包含一个抽象方法(除了从Object类继承的方法以外),用于执行具体的操作。

  • 该方法的参数和返回值类型可以根据实际需求进行定义。

例如,下面的代码定义了一个名为MyFunction的函数式接口,表示接受两个整数参数并返回一个整数结果的操作:

@FunctionalInterface
public interface MyFunction {
    int apply(int x, int y);
}

在上述代码中,使用@FunctionalInterface注解标记该接口为函数式接口,并定义了一个抽象方法apply(),用于接受两个整数参数x和y,执行具体的操作,并返回一个整数结果。

然后,可以使用Lambda表达式或方法引用对该接口进行实现,例如:

MyFunction add = (x, y) -> x + y;
int result = add.apply(5, 3);
System.out.println(result); // 输出8

MyFunction multiply = (x, y) -> x * y;
result = multiply.apply(5, 3);
System.out.println(result); // 输出15

在上述代码中,首先创建了两个MyFunction对象add和multiply,并使用Lambda表达式实现它们的apply()方法。然后分别调用apply()方法,用于执行加法和乘法操作,并返回相应的结果。

需要注意的是,当定义自己的函数式接口时,应该遵循单一职责原则,确保接口只包含一个抽象方法,并且根据实际需求定义参数和返回值类型。此外,使用@FunctionalInterface注解可以帮助编译器检查接口是否满足函数式接口的要求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值