前言

lambda 中了解了什么是函数式接口,以及 @FunctionalInterface 注解。

我们知道函数式接口中,有且只有一个抽象方法的接口,但可以有多个非抽象方法的接口。

@FunctionalInterface 注解是可以检查一个接口是否为函数式接口。只是在编译时强制规范使用。 如果接口是函数接口,编译通过;如果不是,编译失败。

我们自定义函数式接口时,@FuncationalInterface 注解是可选的,就算我们不写这个注解,只要保证是函数式接口也是可以的。但是建议加上

Java 8java.util.function 包下预定了大量的函数式接口供我们使用。常用的有:

  • 生产型 Supplier 接口
  • Function 接口
  • Consumer 接口
  • Predicate 接口

生产型 Supplier

java.util.function.Supplier<T> 接口仅包含一个无参的方法 T get()。用来获取一个泛型参指定类型的对象数据。

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

案例

@Test
public void test() {
    String string = supplierGet(() -> {
        return "supplier test";
    });
    System.out.println(string);
}

private static <T> T supplierGet(Supplier<T> sup) {
	return sup.get();
}

消费型 Consumer

java.util.function.Consumer<T> 接口与 Supplier 接口相反,它是消费一个数据,不产生输出,其类型是一个泛型。Consumer 中包含抽象方法void accept(T t) 意思接受一个指定泛型的数据进行处理,此外还有一个默认实现方法 Consumer<T> andThen(Consumer<? super T> after)


@FunctionalInterface
public interface Consumer<T> {
    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

案例_accept

@Test
    public void test() {
        consumerAccept("qweqweqwe", (item) -> {
            String s = new StringBuilder(item.toString()).reverse().toString();
            System.out.println(s);
        });
    }

    private static <T> void consumerAccept(T name, Consumer<T> com) {
        com.accept(name);
    }
}

这里无论 Consumer 都会将其做一次反转后,进行打印。

案例_andThen

@Test
public void test2() {
    consumerAndThen("qwE123", (item) -> {
        System.out.println("先执行了我");
        String s = new StringBuilder(item.toString()).reverse().toString();
        System.out.println(s);
    }, item -> {
        System.out.println("后执行了我");
        String s = item.toUpperCase().toLowerCase();
        System.out.println(s);
    });
}

private static <T> void consumerAndThen(T name, Consumer<T> com, Consumer<T> com2) {
    com.andThen(com2).accept(name);
}

输出结果

先执行了我
321Ewq
后执行了我
qwe123

这里需要注意的点是:

  1. 都是对原数据进行了操作,如果是基本类型值不变,如果是引用对象,只修改了引用对象的内部值。
  2. consumer 内部修改方法剧本变量的值,会提示异常Variable used in lambda expression should be final or effectively final。这是一个隐式的 final
  3. 这里可以做链式消费数据,但是需要主要处理对象的主体。

判断型 Predicate

java.util.function.Predicate<T> 接口是接受一个特定泛型的数据,从而获得一个 boolean 结果。其中包含一个抽象方法 boolean test(T t), 根据传入参数做检查后,返回true/false。2


@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);
    }
}

案例_test

@Test
public void test() {
    boolean checkBool = predicateTest("str", item -> {
        if (item instanceof String) {
            return true;
        }
        return false;
    });
    System.out.println(checkBool);
}

private static <T> boolean predicateTest(T obj, Predicate<T> predicate) {
    return predicate.test(obj);
}

案例_negate

Predicate 提供了一个 negate,意为取反,即将返回boolean进行非处理。

@Test
public void tes2() {
    boolean checkBool = predicateNegate("str", item -> {
        if (item instanceof String) {
            return true;
        }
        return false;
    });
    System.out.println(checkBool);
}

private static <T> boolean predicateNegate(T obj, Predicate<T> predicate) {
    // 等效于 !predicate.test(obj);
    return predicate.negate().test(obj);
}

案例_and

Predicate 接口中有一个方法 and,表示并且关系,同时满足返回 TRUE


/**
     * 1. 判断是否为String类型
     * 2. 判断是否以STR开始
     * 两个调价你必须同时满足
     */
@Test
public void tes3() {
    boolean checkBool = predicateAnd(Integer.valueOf(123), item -> {
        System.out.println("type");
        if (String.class.isInstance(item) ) {
            return true;
        }
        return false;
    }, item -> {
        System.out.println("starts");
        if (item.toString().toUpperCase().startsWith("STR")) {
            return true;
        }
        return false;
    });
    System.out.println(checkBool);
}

private static <T> boolean predicateAnd(T obj, Predicate<T> predicate, Predicate<T> predicate2) {
    // 等效于 predicate.test(obj) && predicate2.test(obj);
    return predicate.and(predicate2).test(obj);
}

案例_or

Predicate 接口中有一个方法 or,表示或关系,满足一个返回 TRUE


/**
     * 1. 判断是否为Integer类型
     * 2. 判断是否以STR开始
     * 两个条件满足一个
     */
@Test
public void test4() {
    boolean checkBool = predicateOr(String.valueOf("STR111"), item -> {
        System.out.println("type");
        if (Integer.class.isInstance(item)) {
            return true;
        }
        return false;
    }, item -> {
        System.out.println("starts");
        if (item.toString().toUpperCase().startsWith("STR")) {
            return true;
        }
        return false;
    });
    System.out.println(checkBool);
}

private static <T> boolean predicateOr(T obj, Predicate<T> predicate, Predicate<T> predicate2) {
    // 等效于 predicate.test(obj) || predicate2.test(obj);
    return predicate.or(predicate2).test(obj);
}

类型转换 Function

ava.util.function.Function<T,R> 用来根据一个类型的数据得到另一个类型的数据,前者 T 称为前置条件/传入参数,后者 R 成为后置条件/返回参数。提供了一个最主要的抽象方法 R apply(T t),根据 T 类型的数据获取 R 类型的结果。使用场景:类型转换。


@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);

    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

案例_apply


@Test
public void test() {
    Integer integer = functionTest("123123", item -> {
        return Integer.valueOf(item);
    });
    System.out.println(integer);
}

public static <T, R> R functionTest(T obj, Function<T, R> function) {
    return function.apply(obj);
}

案例_compose

接口中的默认方法 compose 用来进行组合操作。传入一个 function 先执行,并将处理结果传入下一个 function


/**
     * 1. 执行apply(4),将“4” 传入到fc2 转换为 Integer输出
     * 2. 在执行fc1 的apply方法,将Integer 4传入。
     */
@Test
public void test2() {
    Function<Integer, Integer> fc1 = i -> i * 2;
    Function<String, Integer> fc2 = i -> Integer.valueOf(i);
    System.out.println(fc1.compose(fc2).apply("4"));
}

案例_andThen

默认方法 andThen 用来进行组合操作。传入一个 function 后执行,并将处理结果传入下一个 function。与compose 功能相反,andThen 添加到后面执行,compose 插入到前面执行


/**
     * 1. 接收到 int 4 后,乘以2后,得出8返回
     * 2. 将 int 8 传入,转换为 String 返回
     */
@Test
public void test3() {
    Function<Integer, Integer> fc1 = i -> i * 2;
    Function<Integer, String> fc2 = i -> i + "";
    System.out.println(fc1.andThen(fc2).apply(4));
}