Java函数式接口

Functional Interface

函数式接口。在Java中什么是函数式接口?简单地说,函数式接口就是只有一个抽象方法地接口。Java的函数式接口与函数式编程有着重要的联系。函数式编程是一种编程范式。Java是一款完全面向对象的编程语言。面向对象和函数式编程一样它们都是一种编程范式。所谓编程范式,就是我们如何去组织我们的代码。

函数式编程最大的特点就是,函数(Function)为一等公民。所谓一等公民,说明了它在编程语言组成元素中的重要性。我们传统的编程语言中大部分都是将**值(Value)**作为一等公民。值(Value)的简单理解就是变量(Variable)。而函数方法大多以API的方式去处理和传递值,类和结构体就像是一个包裹,它们负责如何去组合值。函数式编程让函数和值收到了平等的对待。

Java中的函数式接口

Java最开始也是只将值作为一等公民的编程语言。但是随着函数式编程的流行以及它所带来的便利为大家所喜爱。Java在JDK1.8版本推出了函数式编程的解决方案,那就是函数式接口。Java作为一门高级语言,它有着极高的安全性,但是它没有C/C++这种底层语言的灵活性。在C/C++中我们可以传递一个函数的引用地址,进而将函数地位提升。但是Java没有指针,正是这一点,使得在Java中传递函数变得困难。但是Java可以通过接口的方式结Lambda表达式实现函数式编程。

四大函数式接口

在JDK1.8中,函数式接口被放置在了java.util.function包下。在这个包下有很多函数式接口。但是有四个常见比较重要的接口它们分别是:

  1. Function<T, R> /* 函数型接口 */
    
  2. Consumer<T> /* 消费型接口 */
    
  3. Supplier<T> /* 供给型接口 */
    
  4. Predicate<T> /* 断定型接口 */
    

Function 函数型接口

Java函数式接口_第1张图片
Source Code:

@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,函数型接口需要接收一个参数,并返回一个值。

/* 匿名内部类形式 */
Function<String, String> upper1 = new Function<String, String>() {
            @Override
            public String apply(String s) {
               return s.toUpperCase();
            }
        };

/* Lambda表达式 */
Function<String, String> upper2 = (in)->{ return in.toUpperCase(); };

String ret1 = upper1.apply("hello world");
String ret2 = upper2.apply("java");

这样我们就可以间接的将一个方法和变量的地位平等处理了,进而完成函数式编程。如果你有JavaScript编程经验,你会对第二种Lambda表达式的形式感到亲切。没错Java也可以像JavaScript一样,去定义函数类型的变量。

Consumer 消费型接口

Java函数式接口_第2张图片
Source Code

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

正如其名,消费型接口没有返回值,他只负责消费。消费型接口在一些大型框架例如Duubo,ZooKeeper中有着广泛的应用。我们平时会用到消费型接口是在遍历一个集合的时候。

List<Integer> list = new ArrayList<>();
for ( int i=0; i<10; ++i ) {
    list.add( i );
}

/* 循环索引遍历 */
for ( int i=0; i<list.size(); ++i ) {
    System.out.println( list.get(i) );
}
for ( int i : list ) {
    System.out.println( i );
}

/* 消费型接口遍历 */
list.forEach( System.out::println ); /* JDK8中 使用 :: 代表传递方法的引用 */
list.forEach( t-> {
    System.out.println(t)
})

集合APIforEach所接受的就是一个消费型接口的参数。这再一次印证了函数作为一等公民。

Supplier 供给型接口

Java函数式接口_第3张图片
Source Code

@FunctionalInterface
public interface Supplier<T> {

    T get();
}

供给型接口不接收任何参数,它只负责返回一个类型的值。

Predicate 断定型接口

Java函数式接口_第4张图片
Source Code

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

正如它的名字一样,断定型接口是用来做判断的。在JDK1.8的流(Stream)式编程中大量的使用了断定型接口。

/**
从数组[0,1,2,3,4,5,6,7,8,9]中过滤出一个只包含偶数的数组。
*/

List<Integer> list = new ArrayList<>();

for ( int i=0; i<10; ++i ) {
    list.add( i );
}

Stream<Integer> stream = list.stream();

Stream<Integer> fl = stream.filter(t -> {
    if (t % 2 == 0)
        return true;
    else
        return false;
});

fl.forEach(System.out::println);

你可能感兴趣的:(Java)