jdk8函数接口

java8 新特性推出的 Lambda 表达式,即函数式编程,相信很多开发胸弟都会使用了,但是什么是函数式编程呢?别问我,我也不知道标准的定义。其核心思想是:使用不可变值和函数,函数对一个值进行处理,映射成另一个值

函数接口

java8之前接口类只有方法的定义,没有实现的,Java8对接口提供默认方法的新特性。一个接口类可以定义n个抽象方法,但如果有 @FunctionalInterface 注解修饰就不一样了,该注释会强制编译检查一个接口是否符合函数接口的标准。如果该注释添加给一个枚举类型、类或另一个注释,或者接口包含不止一个抽象方法,编译就会报错。@FunctionalInterface 注解修饰的接口就是被定义成函数接口。

常用的函数接口

平时开发中常用的函数接口有无返回值的Consumer,返回值为Boolean的Predicate,把入参T映射成R返回值的Function 和返回实例对象的Supplier。接下来我们一起分析这四个函数接口类的源码以及简单的使用,先创建一个后面需要用到的实体类 Griez。

public class Griez implements Serializable {
    private int age;
    private String name;
    public Griez(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public Griez setAge(int age) {
        this.age = age;
        return this;
    }

    public String getName() {
        return name;
    }

    public Griez setName(String name) {
        this.name = name;
        return this;
    }
}

定义一个法国球星格子(我最喜欢的球员)类,为了简单这里只有名字和年龄,他的能力值和薪资就不展示出来了,怕吓到大家。

Consumer

@FunctionalInterface
public interface Consumer<T> {
		// 执行时需要调用传入的实现
    void accept(T t);

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

Consumer函数接口有两个方法,抽象方法accept需要调用者自己实现;andThen默认方法封装了两个Consumer执行顺序的Consumer实例,先执行本实例的accept,再执行参数after的accept方法。

    public static void main(String[] args) {
        Consumer<Griez> consumer = griez -> System.out.println(griez.getName() + griez.age);
        Consumer<Griez> afterConsumer = griez -> System.out.println(griez.getAge());
        Consumer<Griez> then = consumer.andThen(afterConsumer);
        then.accept(new Griez(29, "wolf"));
    }

第1,2行创建Consumer实例,并实现了accept方法。记得刚毕业出来面试有个面试官问我接口能不能创建实例,我给他的回答是:“你说呢?”。

Predicate

@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 方法需要自定义逻辑,返回一个boolean值,该函数接口是做判断用途的。and 方法是两个Predicate 逻辑与判断;negate 方法是逻辑非判断;or 方法是两个 Predicate 逻辑或判断;isEqual 方法是判断targetRef是否与本实例相同。

public static void main(String[] args) {
    Predicate<Griez> predicate= griez -> griez.getAge() > 18;
    System.out.println("Griez已经成年了 : " + predicate.test(new Griez(29, "griez")));
}

test返回Boolean值。

Function

@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 方法接收一个T参数,然后一个R,该方法是类型映射作用。compose 方法是组装了两个Function执行顺序行为Function对象,先执行参数的Function在执行本实例Function。andThen 跟 compose执行顺序相反。identity 方法是返回参数本身。

public static void main(String[] args) {
    Function function = o -> new Griez(20, "Female");
    System.out.println(function.apply(new Griez(29, "griez").getName()));
}

一个大老爷进去变成一个年轻小姐姐出来,变态的程序员。

Supplier

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

该函数接口看上去就比较寒颤了,只有一个方法。get 方法作用如名字一个,伸手党来的,获取一个实例。

public static void main(String[] args) {
    Supplier<Griez> supplier = () -> new Griez(29, "griez");
    System.out.println(supplier.get());
}

获取一个Griez对象。

posted @ 2020-03-01 11:46  Griez  阅读(...)  评论(...编辑  收藏