Java 8 BiFunction 函数接口

这篇文章属于 Java 8 教程(LTS)系列教程,点击阅读更多相关文章。

在 Java 8 中,BiFunction 是一个函数式接口,它和 Function 函数接口十分相似,它可以接受两个不同类型的参数(泛型 T 类型和 泛型 U 类型),然后返回一个其他类型的值(泛型 R 类型)。

相关阅读Java 8 Function 函数接口

BiFunction 在 Java 8 中的源码。

package java.util.function;

import java.util.Objects;

@FunctionalInterface
public interface BiFunction<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));
    }
}

1. BiFunction

示例:接收两个字符串,返回字符串的长度和;接收两个数字,返回 x 的 y 次方。

package com.wdbyte;

import java.util.function.BiFunction;

public class Java8BiFunction {

    public static void main(String[] args) {
        // 两个字符串长度和
        BiFunction<String, String, Integer> lengthBiFun = (s1, s2) -> s1.length() + s2.length();
        Integer length = lengthBiFun.apply("java", "www.byte.com");
        System.out.println(length);

        // x 的 y 次方
        BiFunction<Integer, Integer, Double> powBiFun = (i1, i2) -> Math.pow(i1, i2);
        Double pow = powBiFun.apply(2, 10);
        System.out.println(pow);
    }
}

输出结果:

16
1024.0

2. BiFunction 和 Function

BiFunction 中的 andThen 方法可以接受一个 Function 参数,使用 andThen 时的运算逻辑,是把 BiFunction 的结果传入 Function 运算。

示例1:使用 BiFunction ,输入两个字符串,返回两个字符串的长度和;长度和输入到 Function,拼接上字符串 ”长度和:“ 返回,然后输出这个结果。

package com.wdbyte;

import java.util.function.BiFunction;
import java.util.function.Function;

public class Java8BiFunctionAndThen {

    public static void main(String[] args) {
        // 两个字符串长度和
        BiFunction<String, String, Integer> lengthBiFun = (s1, s2) -> s1.length() + s2.length();
        Function<Integer, String> function = s -> "长度和:" + s;

        String result = lengthBiFun.andThen(function).apply("java", "www.byte.com");
        System.out.println(result);
    }
}

输出结果:

长度和:16

示例 2:这里两个函数式接口还可以进一步抽象,抽象成更通用的转换方法。

package com.wdbyte;

import java.util.function.BiFunction;
import java.util.function.Function;

public class Java8BiFunctionAndThen2 {

    public static void main(String[] args) {
        String result = convert("java", 
                                "www.wdbyte.com", 
                                (a1, a2) -> a1.length() + a2.length(), 
                                r1 -> "长度和:" + r1);
        System.out.println(result);
    }

    public static <T1, T2, R1, R2> R2 convert(  T1 t1,
                                                T2 t2,
                                                BiFunction<T1, T2, R1> biFunction,
                                                Function<R1, R2> function) {
        return biFunction.andThen(function).apply(t1, t2);
    }
}

输出结果:

长度和:16

示例 3:上面的例子已经十分通用了,可以传入任意类型组合操作,比如求两个数字的和。

public static void main(String[] args) {
    String convert = convert(1, 2,
        (a1, a2) -> a1 + a2,
        r1 -> "和是:" + r1);
    System.out.println(convert);
}

public static <T1, T2, R1, R2> R2 convert(  T1 t1,
                                            T2 t2,
                                            BiFunction<T1, T2, R1> biFunction,
                                            Function<R1, R2> function) {
    return biFunction.andThen(function).apply(t1, t2);
}

输出结果:

和是:3

3. 工厂模式

准备要创建的对象类。

package com.wdbyte;
public class Dog {
    private String name;
    private Integer age;

    public Dog() {
    }
    public Dog(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    // 省略 get set toString
}

示例:使用 BiFunction 构建工厂模式创建狗类对象。

package com.wdbyte;

import java.util.function.BiFunction;

public class JavaBiFunctionFactory {

    public static void main(String[] args) {
        System.out.println(dogFactory("牧羊犬", 1, Dog::new));
        System.out.println(dogFactory("哈士奇", 2, Dog::new));
    }

    public static <R extends Dog> Dog dogFactory(String name, Integer age, BiFunction<String, Integer, R> biFunction) {
        return biFunction.apply(name, age);
    }
}

注意Dog::new 输入两个参数,要有对应的构造函数 public Dog(String name, Integer age) 与之对应。

输出结果:

Dog{, name='牧羊犬', age=1}
Dog{, name='哈士奇', age=2}

4. 扩展玩法

彻底掌握 BiFunction 的使用,随心构建一个使用 BiFunction 完成的集合过滤函数。

示例:构建一个可以过滤指定集合条件的 filter 方法。

package com.wdbyte;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiFunction;

public class Java8BiFunctionFilter {

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
        // 筛选 2 的倍数
        List<Integer> result1 = filter(list, 2, Java8BiFunctionFilter::divisible);
        System.out.println(result1);
        // 筛选 3 的倍数
        List<Integer> result2 = filter(list, 3, Java8BiFunctionFilter::divisible);
        System.out.println(result2);
        // 筛选 4 的倍数
        List<Integer> result3 = filter(list, 4, Java8BiFunctionFilter::divisible);
        System.out.println(result3);

        // 筛选长度为 4 的字符串
        List<String> stringList = Arrays.asList("java", "node", "c++", "rust", "www.wdbyte.com");
        List<String> stringList1 = filter(stringList, 4, (s, n) -> s.length() == 4 ? true : null);
        System.out.println(stringList1);
    }

    /**
     * n1 / n2 是否可以除尽
     *
     * @param n1
     * @param n2
     * @return
     */
    private static Boolean divisible(Integer n1, Integer n2) {
        if (n1 % n2 == 0) {
            return true;
        }
        return null;
    }

    /**
     * 过滤集合 List 中,符合 BiFunction<T, U, R> biFunction 的元素
     *
     * @param list
     * @param u
     * @param biFunction
     * @param <T>
     * @param <U>
     * @param <R>
     * @return
     */
    private static <T, U, R> List<T> filter(List<T> list,
                                         U u,
                                         BiFunction<T, U, R> biFunction) {
        List<T> resultList = new ArrayList<>();
        for (T t : list) {
            if (biFunction.apply(t, u) != null) {
                resultList.add(t);
            }
        }
        return resultList;
    }
}

输出结果:

[2, 4, 6, 8, 10, 12]
[3, 6, 9, 12]
[4, 8, 12]
[java, node, rust]

参考