概述

函数式接口在Java中是指:有且仅有一个抽象方法的接口

Lambda表达式是用来实现SAM接口的,所谓SAM就是Single Abstract Method,即该接口中只有一个抽象方法需要实现,当然该接口可以包含其他非抽象方法。

从应用层面来讲,Java中的Lambda表达式可以看做是接口对应的匿名内部类的简化格式,但是二者在原理上不同。

@FunctionalInterface注解

@Override 注解的作用类似,Java 8中专门为函数式接口引入了一个新的注解:@FunctionalInterface,该注解可用于一个接口的定义上:

@FunctionalInterface
public interface MyFunctionalInterface {
    void myMethod();
}

一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。不过,即使不使用该注解,只要满足函数式接口的定义,这仍然是一个函数式接口,使用起来都一样。

JDK1.8之前,核心类库中就已经存在很多SAM接口了,例如:

(1)java.lang.Runnable

(2)java.util.concurrent.Callable

(3)java.util.Comparator

(4)java.lang.Comparable

(5)java.lang.Iterable

(6)java.io.FileFilter等

但是在JDK1.8,只有部分方法加了 @FunctionalInterface,那些没有加 @FunctionalInterface 的SAM接口,存在将来增加抽象方法变成非SAM接口的风险,因此建议只对加了 @FunctionalInterface 的接口使用Lambda表达式实现。

JDK1.8在 java.util.function 包增加了很多函数式接口,不过他们可以归纳为四类:供给型接口消费型接口功能型接口判断型接口,一共43个

供给型接口

这类接口名以单词Supplier结尾,Supplier:供应者。对应的Lambda表达式需要“对外提供”数据。

这类接口的抽象方法特点:无参,有返回值;

接口名

抽象方法

描述

Supplier

T get()

返回一个对象

BooleanSupplier

boolean getAsBoolean()

返回一个boolean值

DoubleSupplier

double getAsDouble()

返回一个double值

IntSupplier

int getAsInt()

返回一个int值

LongSupplier

long getAsLong()

返回一个long值

典型代表—Supplier接口

java.util.function.Supplier<T>接口,对应的Lambda表达式需要对外提供一个符合泛型类型的对象数据。接口定义:

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

抽象方法 : T get()

用来获取一个泛型参数指定类型的对象数据。

代码示例:

public class SupplierDemo {
    public static void main(String[] args) {
        String strA = "Hello ";
        String strB = "World";
        
        //传参:Supplier<String> supplier = () -> strA + strB; 
        //调用重写的get方法:get() {return strA + strB;}
        String result = getString(() -> strA + strB);
        System.out.println(result);
    }
​
    static String getString(Supplier<String> supplier) {
        return supplier.get();
    }
}

求数组元素最大值

使用Supplier接口作为方法参数类型,通过Lambda表达式求出int数组中的最大值,接口的泛型使用java.lang.Integer类。

代码示例:

public class IntArrayTest {
    public static void main(String[] args) {
        int[] array = {10, 5, 12, 3, 7, 15};
        pringMax(() -> {
            int max = array[0];
            for (int i = 1; i < array.length; i++) {
                if (array[i] > max) {
                    max = array[i];
                }
            }
            return max;
        });
    }
​
    static void pringMax(Supplier<Integer> supplier) {
        int max = supplier.get();
        System.out.println(max);
    }
}

消费型接口

这类接口名称以单词Consumer结尾,Consumer:消费者。对应的Lambda表达式需要接收参数来完成功能。

这类接口的抽象方法特点:有参、无返回值

接口名

抽象方法

描述

Consumer

void accept(T t)

接收一个对象用于完成功能

BiConsumer<T,U>

void accept(T t, U u)

接收两个对象用于完成功能

DoubleConsumer

void accept(double value)

接收一个double值

IntConsumer

void accept(int value)

接收一个int值

LongConsumer

void accept(long value)

接收一个long值

ObjDoubleConsumer

void accept(T t, double value)

接收一个对象和一个double值

ObjIntConsumer

void accept(T t, int value)

接收一个对象和一个int值

ObjLongConsumer

void accept(T t, long value)

接收一个对象和一个long值

典型代表—Consumer接口

java.util.function.Consumer<T> :接收一个对象,来执行相关操作,其数据类型由泛型参数决定。

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

抽象方法:void accept(T t)

接收一个对象,来执行相关操作

public class ConsumerDemo {
    public static void main(String[] args) {
        String str = "Hello world";
        //字符串转为小写
        convert(s -> System.out.println(s.toLowerCase()), str);
    }
​
    static void convert(Consumer<String> consumer, String str) {
        consumer.accept(str);
    }
}

默认方法:andThen,如果一个方法的参数和返回值全都是 Consumer 类型,那么就可以:接收一个数据的时候,首先做一个操作,然后再做一个操作,实现组合。源码:

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

代码示例:大小写转换

public class ConsumerDemo {
    public static void main(String[] args) {
        String str = "Hello world";
        //Consumer<String> c1 = s1 -> System.out.println(s1.toLowerCase());
        //Consumer<String> c2 = s2 -> System.out.println(s2.toUpperCase());
        convert(s1 -> System.out.println(s1.toLowerCase()),
                s2 -> System.out.println(s2.toUpperCase()), str);
    }
​
    static void convert(Consumer<String> c1, Consumer<String> c2, String str) {
        c1.accept(str);
        c2.accept(str);
        //andThen方法返回值为Consumer<T>接口的实现类对象:(T t) -> { accept(t); after.accept(t); }
        //先小写后大写:c1.accept(str); c2.accept(str);
        c1.andThen(c2).accept(str);
        //先大写后小写:c2.accept(str); c1.accept(str)
        c2.andThen(c1).accept(str);
    }
}

上面代码中,c1.andThen(c2) 返回Consumer接口的实现类对象,该对象调用accept(str),此时重写的accept(str)方法的方法体为{c1.accept(str); c2.accept(str)}

判断型接口

这类接口名称以单词Predicate结尾,Predicate:断言、判断。对某种类型的数据进行判断,从而得到一个boolean值结果。

这类接口的抽象方法特点:有参、返回值类型是boolean

接口名

抽象方法

描述

Predicate

boolean test(T t)

接收一个对象

BiPredicate<T,U>

boolean test(T t, U u)

接收两个对象

DoublePredicate

boolean test(double value)

接收一个double值

IntPredicate

boolean test(int value)

接收一个int值

LongPredicate

boolean test(long value)

接收一个long值

典型代表—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);
    }
    //两个对象的equals方法比较
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

抽象方法:boolean test(T t),用于条件判断的场景,条件判断的标准是传入的Lambda表达式逻辑

代码示例:

输出正数数组中的所有偶数:

public class PredicateTest {
    public static void main(String[] args) {
        int[] array = {0, 1, 2, 3, 4, 6, 7, 10, 15, 20};
        System.out.println("所有偶数:");
        eval(array, n -> n%2 == 0);
    }

    static void eval(int[] array, Predicate<Integer> p) {
        for (int i : array) {
            if (p.test(i)) {
                System.out.println(i);
            }
        }
    }
}

默认方法:and,既然是条件判断,就会存在与、或、非三种常见的逻辑关系。其中将两个 Predicate 条件使用“与”逻辑连接起来实现“并且”的效果时,可以使用default方法 and ,源码:

default Predicate<T> and(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) && other.test(t);
}

输出大于等于6所有偶数:

public class PredicateTest {
    public static void main(String[] args) {
        int[] array = {0, 1, 2, 3, 4, 6, 7, 10, 15, 20};
        System.out.println("大于等于6所有偶数:");
        eval(array, m -> m >= 6, n -> n%2 == 0);
    }

    static void eval(int[] array, Predicate<Integer> p1, Predicate<Integer> p2) {
        for (int i : array) {
            if (p1.and(p2).test(i)) {
                System.out.println(i);
            }
        }
    }
}

默认方法:or,与 and 的“与”类似,默认方法 or 实现逻辑关系中的,源码:

default Predicate<T> or(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) || other.test(t);
}

输出大于6的整数或偶数:

public class PredicateTest {
    public static void main(String[] args) {
        int[] array = {0, 1, 2, 3, 4, 6, 7, 10, 15, 20};
        System.out.println("大于6的整数或偶数:");
        eval(array, m -> m >= 6, n -> n%2 == 0);
    }

    static void eval(int[] array, Predicate<Integer> p1, Predicate<Integer> p2) {
        for (int i : array) {
            if (p1.or(p2).test(i)) {
                System.out.println(i);
            }
        }
    }
}

默认方法:negate,实现逻辑关系中的,源码:

default Predicate<T> negate() {
    return (t) -> !test(t);
}

输出不大于7的整数:

public class PredicateTest {
    public static void main(String[] args) {
        int[] array = {0, 1, 2, 3, 4, 6, 7, 10, 15, 20};
        System.out.println("不大于7的整数:");
        eval(array, n -> n > 7);
    }

    static void eval(int[] array, Predicate<Integer> p) {
        for (int i : array) {
            if (p.negate().test(i)) {
                System.out.println(i);
            }
        }
    }
}

功能型接口

这类接口名称以单词Function或Operator结尾,用于完成某项功能并返回数据

这类接口的抽象方法特点:有参数、有返回值

接口名

抽象方法

描述

Function<T,R>

R apply(T t)

接收一个T类型对象,返回一个R类型对象结果

UnaryOperator

T apply(T t)

接收一个T类型对象,返回一个T类型对象结果

DoubleFunction

R apply(double value)

接收一个double值,返回一个R类型对象

IntFunction

R apply(int value)

接收一个int值,返回一个R类型对象

LongFunction

R apply(long value)

接收一个long值,返回一个R类型对象

ToDoubleFunction

double applyAsDouble(T value)

接收一个T类型对象,返回一个double

ToIntFunction

int applyAsInt(T value)

接收一个T类型对象,返回一个int值

ToLongFunction

long applyAsLong(T value)

接收一个T类型对象,返回一个long值

DoubleToIntFunction

int applyAsInt(double value)

接收一个double值,返回一个int值

DoubleToLongFunction

long applyAsLong(double value)

接收一个double值,返回一个long值

IntToDoubleFunction

double applyAsDouble(int value)

接收一个int值,返回一个double值

IntToLongFunction

long applyAsLong(int value)

接收一个int值,返回一个long值

LongToDoubleFunction

double applyAsDouble(long value)

接收一个long值,返回一个double值

LongToIntFunction

int applyAsInt(long value)

接收一个long值,返回一个int值

DoubleUnaryOperator

double applyAsDouble(double operand)

接收一个double值,返回一个double值

IntUnaryOperator

int applyAsInt(int operand)

接收一个int值,返回一个int值

LongUnaryOperator

long applyAsLong(long operand)

接收一个long值,返回一个long值

BiFunction<T,U,R>

R apply(T t, U u)

接收一个T类型和一个U类型对象,返回一个R类型对象

BinaryOperator

T apply(T t, T u)

接收两个T类型对象,返回一个T类型对象

ToDoubleBiFunction<T,U>

double applyAsDouble(T t, U u)

接收一个T类型和一个U类型对象,返回一个double值

ToIntBiFunction<T,U>

int applyAsInt(T t, U u)

接收一个T类型和一个U类型对象,返回一个int值

ToLongBiFunction<T,U>

long applyAsLong(T t, U u)

接收一个T类型和一个U类型对象,返回一个long值

DoubleBinaryOperator

double applyAsDouble(double left, double right)

接收两个double值,返回一个double值

IntBinaryOperator

int applyAsInt(int left, int right)

接收两个int值,返回一个int值

LongBinaryOperator

long applyAsLong(long left, long right)

接收两个long值,返回一个long值

典型代表—Function接口

java.util.function.Function<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;
    }
}

抽象方法:R apply(T t)

Function接口中最主要的抽象方法为:R apply(T t),根据类型T的参数获取类型R的结果。

类似于数学中的函数: y = f ( x ) y = f(x) y\=f(x) 代码演示:将String类型转换为Integer类型。

public class FuntionTest {
    public static void main(String[] args) {
        parse(s -> Integer.parseInt(s), "10");
    }

    static void parse(Function<String, Integer> func , String str) {
        int num =  func.apply(str);
        System.out.println(num);
    }
}

默认方法:compose,源码:

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对象执行对应的apply方法,然后使用当前的Function对象的执行对应的apply方法

代码演示:先将字符串与字符’0’拼接,再转为整数

public class FuntionTest {
    public static void main(String[] args) {
        parse(s1 -> Integer.parseInt(s1), s2 -> s2 + '0', "10");
    }
​
    static void parse(Function<String, Integer> func1, Function<String, String> func2 , String str) {
        //先用传入的 func2 = s2 -> s2 + '0'; 执行apply
        //然后用当前的 func1 = s1 -> Integer.parseInt(s1); 执行apply
        int num = func1.compose(func2).apply(str);
        System.out.println(num);
    }
}

默认方法:andThen,源码:

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

andThen方法接收一个Function类型的参数,先用当前的Function对象的执行对应的apply方法,然后使用传入的Function对象执行对应的apply方法

代码演示:先将字符串转为整数,然后将此整数乘以10

public class FuntionTest {
​
    public static void main(String[] args) {
        parse(s -> Integer.parseInt(s), i -> i * 12, "10");
    }
​
    static void parse(Function<String, Integer> func1, Function<Integer, Integer> func2 , String str) {
        //先用当前的 func1 = s1 -> Integer.parseInt(s1); 执行apply
        //然后用传入的 func2 = i -> i * 12; 执行apply
        int num = func1.andThen(func2).apply(str);
        System.out.println(num);
    }
}