Java Lambda从入门到精通三 Java API中的函数式接口

Java8中提供了3大类函数式接口:PredicateConsumerFunction

这三大类函数式接口基本覆盖了我们开发中大多数需要使用lambda的场景,不需要我们再自己定义函数式接口了,也就是说我们第二节的例子中定义的函数式接口AppleFormatter,是可以不用定义的。

@FunctionalInterface
public interface AppleFormatter {
    String accept(Apple apple);
}

我们下面就来看一下这三种函数式接口。

Predicate

提供一个test方法,方法入参为泛型T,返回布尔类型,也就是这个方法可以用来做逻辑判断。

@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
}   

使用Predicate对第二节的例子进行改造。

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

/**
 * @Auther: www.itzhimei.com
 * @Description: Predicate
 */
public class Lambda3_3 {

    public static void main(String[] args) {
        List<Apple> apples = new ArrayList<>();
        Apple a1 = new Apple("红",155);
        Apple a2 = new Apple("绿",136);
        Apple a3 = new Apple("红",169);
        apples.add(a1);
        apples.add(a2);
        apples.add(a3);

        Predicate<Apple> gr150 = (Apple a) -> a.getWeight() > 150;
        printApple(apples, gr150,"是否是大于150g的苹果:");

        Predicate<Apple> eq155 = (Apple a) -> a.getWeight() == 155;
        printApple(apples, eq155, "是否等于155g的苹果:");
    }

    public static void printApple(List<Apple> apples, Predicate<Apple> af, String info) {
        for(Apple a : apples) {
            System.out.println(info + af.test(a));
        }
    }
}

输出结果:

是否是大于150g的苹果:true
是否是大于150g的苹果:false
是否是大于150g的苹果:true

是否等于155g的苹果:true
是否等于155g的苹果:false
是否等于155g的苹果:false

Consumer

提供一个accept方法,方法参数为泛型T,返回void,这个方法是做逻辑处理并不会返回任何结果。

@FunctionalInterface
public interface Consumer<T> {

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

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
 * @Auther: www.itzhimei.com
 * @Description: Consumer
 */
public class Lambda3_3_Consumer {

    public static void main(String[] args) {
        List<Apple> apples = new ArrayList<>();
        Apple a1 = new Apple("红",155);
        Apple a2 = new Apple("绿",136);
        Apple a3 = new Apple("红",169);
        apples.add(a1);
        apples.add(a2);
        apples.add(a3);
        
        Consumer<Apple> printGr150 = (Apple a) -> System.out.println(a.getWeight() > 150?"重苹果":"轻苹果");
        printApple(apples, printGr150);

    }

    public static void printApple(List<Apple> apples, Consumer<Apple> af) {
        for(Apple a : apples) {
            af.accept(a);
        }
    }
}

输出结果:

重苹果
轻苹果
重苹果

Function

提供一个apply方法,apply方法入参为泛型T,返回为泛型R,这个方法即支持传入参数,也支持返回值,兼具了Predicate和Consumer的特性,而且方法更灵活。

@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);
}  

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * @Auther: www.itzhimei.com
 * @Description: Function
 */
public class Lambda3_3_Function {

    public static void main(String[] args) {
        List<Apple> apples = new ArrayList<>();
        Apple a1 = new Apple("红",155);
        Apple a2 = new Apple("绿",136);
        Apple a3 = new Apple("红",169);
        apples.add(a1);
        apples.add(a2);
        apples.add(a3);

        Function<Apple, String> printWL = (Apple a) -> a.getWeight() > 150?"重苹果":"轻苹果";
        printApple(apples, printWL);

    }

    public static void printApple(List<Apple> apples, Function<Apple, String> af) {
        for(Apple a : apples) {
            System.out.println(af.apply(a));
        }
    }
}

输出结果:

重苹果
轻苹果
重苹果

以上三种函数式接口,还提供了非常多的原始类型的接口:IntPredicate、IntConsumer、IntFunction<R>、LongPredicate、LongConsumer、LongFunction<R>等等。

提供这些类的目的就是避免装箱拆箱,因为Predicate<T>如果是int作为参数,则要用int的对象类型Integer,因为原始类型不支持泛型使用,所以要使用Integer,这时就设计到装箱和拆箱,这有性能上的影响,所以java为开发者提供了多种原始类型的的函数式接口,避免装箱和拆箱。