一文教会你JDK8的函数式编程

JDK8的1个新特性就是支持函数式接口(Functional Interface)。

函数式接口就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。

函数式接口可以被隐式转换为Lambda表达式。

我们也可以自行定义函数式接口,如:

@FunctionalInterface
interface GreetingService{
	void sayMessage(String message);
}

然后通过Lambda表达式来定义接口实现(JAVA8之前一般使用匿名类来实现):

public class GreetingServiceTest {
    public static void main(String[] args) {
        GreetingService greetingService = message -> {
            System.out.println("Hello " + message);
        };
        greetingService.sayMessage("Mary");
    }
}

执行返回:

Hello Mary

JDK8官方也为我们定义了一些常用的函数式接口,如下图所示:

在这里插入图片描述
在这里插入图片描述

接下来,我重点介绍其中比较重要的几个函数式接口。

Function<T, R>

接收1个输入参数,返回1个结果。

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

    // 将T类型转化为R类型
    R apply(T t);

    // 先执行参数传入的Function,再执行本Function
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    // 和compose相反,先执行本Function,再执行参数传入的Function
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    // 静态方法,返回传入的泛型T自身
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}
  • 代码示例
public class FunctionTest {

    public static Integer calculate(Integer i, Function<Integer, Integer> function){
        return function.apply(i);
    }
    
    public static void main(String[] args) {
        Function<Integer, Integer> func1 = i -> {return i+5;};
        Function<Integer, Integer> func2 = i -> {return i*5;};
        System.out.println(calculate(6, func1));
        System.out.println(calculate(6, func2));
        System.out.println(calculate(6, func1.compose(func2)));
        System.out.println(calculate(6, func1.andThen(func2)));
        System.out.println(Function.identity().apply("6+5"));
    }
}

执行输出:

11
30
35
55
6+5

Supplier

生产函数,无参数,返回1个结果。

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

    // 生产1个元素
    T get();
}
  • 代码示例
public class SupplierTest {
    public static void main(String[] args) {
        Supplier<String> supplier = () -> {return "商品";};
        System.out.println(supplier.get());
    }
}

执行输出:

商品

Consumer

消费函数,接收1个输入参数并且无返回的操作。

  • 源码
@FunctionalInterface
public interface Consumer<T> {
	// 消费输入t
    void accept(T t);

	// 先执行本接口的消费逻辑,再执行传入函数的消费逻辑
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}
  • 代码示例
public class ConsumerTest {
    public static void main(String[] args) {
        Consumer<String> consumer1 = s -> {
            System.out.println(s + ",我是消费者1");
        };
        Consumer<String> consumer2 = s -> {
            System.out.println(s + ",我是消费者2");
        };
        consumer1.accept("铁甲小宝");
        System.out.println("################");
        consumer1.andThen(consumer2).accept("铁甲小宝");
    }
}

执行输出:

铁甲小宝,我是消费者1
################
铁甲小宝,我是消费者1
铁甲小宝,我是消费者2

Predicate

断言函数,接受1个输入参数,返回1个布尔值结果。

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

    // 对输入进行断言
    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);
    }

    // 取反
    @SuppressWarnings("unchecked")
    static <T> Predicate<T> not(Predicate<? super T> target) {
        Objects.requireNonNull(target);
        return (Predicate<T>)target.negate();
    }
}
  • 代码示例
public class PredicateTest {
    public static void main(String[] args) {
        // 断言输入值是否大于10
        Predicate<Integer> isSuperTen = i -> {return i>10;};
        System.out.println(isSuperTen.test(11));
        System.out.println(isSuperTen.test(6));
        // 取反,断言输入值是否不大于10
        Predicate<Integer> negate = isSuperTen.negate();
        System.out.println(negate.test(6));
        // 断言输入值是否大于20
        Predicate<Integer> isLowerTwenty = i -> {return i<20;};
        // 断言15是否>10且<20
        System.out.println(isSuperTen.and(isLowerTwenty).test(15));
        // 断言21是否>10且<20
        System.out.println(isSuperTen.and(isLowerTwenty).test(21));
        // 断言21是否>10或<20
        System.out.println(isSuperTen.or(isLowerTwenty).test(21));
    }
}

执行输出:

true
false
true
true
false
true

BiFunction<T, U, R>

接受1个入参T和U,并返回结果R。

  • 源码
@FunctionalInterface
public interface BiFunction<T, U, R> {

    // 根据输入t和u,转化为输出r
    R apply(T t, U u);

    // 先执行本函数,再执行参数传入的函数
    default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t, U u) -> after.apply(apply(t, u));
    }
}
  • 代码示例
public class BiFunctionTest {
    public static void main(String[] args) {
        BiFunction<String, Integer, String> biFunction = (key, value) -> {return (key + ":" + String.valueOf(value));};
        String key = "age";
        Integer value = 18;
        System.out.println(biFunction.apply(key, value));
        Function<String, String> afterFunction = s -> {
            System.out.println("执行后继函数,添加前缀***");
            return "***-" + s;
        };
        System.out.println(biFunction.andThen(afterFunction).apply(key, value));
    }
}

执行输出:

age:18
执行后继函数,添加前缀***
***-age:18

BiConsumer<T, U>

代表了1个接受2个输入参数的操作,并且不返回任何结果。

  • 源码
@FunctionalInterface
public interface BiConsumer<T, U> {

    // 消费2个输入t和u
    void accept(T t, U u);

    // 先执行该函数的消费逻辑,再执行传入函数的消费逻辑
    default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) {
        Objects.requireNonNull(after);

        return (l, r) -> {
            accept(l, r);
            after.accept(l, r);
        };
    }

  • 代码示例
public class BiConsumerTest {

    public static void main(String[] args) {
        BiConsumer<String, Integer> biConsumer1 = (s, i) -> {
            System.out.println("我是消费逻辑1" + "," + s + "," + String.valueOf(i+10));
        };
        BiConsumer<String, Integer> biConsumer2 = (s, i) -> {
            System.out.println("我是消费逻辑2" + "," + s + "," + String.valueOf(i*3));
        };

        biConsumer1.accept("铁甲小宝", 6);
        System.out.println("###########");
        biConsumer1.andThen(biConsumer2).accept("铁甲小宝", 6);

    }
}

执行输出:

我是消费逻辑1,铁甲小宝,16
###########
我是消费逻辑1,铁甲小宝,16
我是消费逻辑2,铁甲小宝,18

BiPredicate<T, U>

对2个输入参数T和U进行断言,返回1个布尔值输出。

  • 源码
@FunctionalInterface
public interface BiPredicate<T, U> {

    // 断言输入t和u
    boolean test(T t, U u);

    // 并操作
    default BiPredicate<T, U> and(BiPredicate<? super T, ? super U> other) {
        Objects.requireNonNull(other);
        return (T t, U u) -> test(t, u) && other.test(t, u);
    }

    // 取反
    default BiPredicate<T, U> negate() {
        return (T t, U u) -> !test(t, u);
    }

    // 或操作
    default BiPredicate<T, U> or(BiPredicate<? super T, ? super U> other) {
        Objects.requireNonNull(other);
        return (T t, U u) -> test(t, u) || other.test(t, u);
    }
}
  • 代码示例
public class BiPredicateTest {
    public static void main(String[] args) {
        // 判断输入1是否大于10,且输入2小于20
        BiPredicate<String, Integer> biPredicate = (s, i) -> {
            return Integer.valueOf(s) > 10 && i < 20;
        };
        System.out.println(biPredicate.test("15", 16));
        System.out.println(biPredicate.test("15", 21));
        System.out.println(biPredicate.test("6", 21));
    }
}

执行输出:

true
false
false

其他函数接口基本原理类似,不再赘述。

之所以今天讲解一下JDK8的函数式编程,主要是为后续的Flink源码解析系列做一些前置知识储备,因为Flink源码里有大量的函数式接口实践。

本文到此结束,谢谢阅读!

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JDK 1.8中,函数接口(Functional Interface)是一个核心概念。如果一个接口有且只有一个未实现的方法,那么这个接口就被称为函数接口。在JDK 1.8中引入了一个新的注解@FunctionalInterface,将这个注解放在接口定义之前,就表示这个接口是一个函数接口。编译器检查该接口是否只有一个未实现的方法,如果定义了多个或者没有定义,编译器报错。尽管这个注解不是必须的,但虚拟机仍然能够识别出函数接口。这个注解的主要作用是防止误操作,加了这个注解之后接口将不允许出现多个未实现的方法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [jdk1.8之函数接口](https://blog.csdn.net/liu_shi_jun/article/details/128562977)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [JDK1.8新特性--函数接口(详解)](https://blog.csdn.net/Saintmm/article/details/109557103)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值