前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入探寻JAVA8 part2:浅谈几个内置的函数式接口

深入探寻JAVA8 part2:浅谈几个内置的函数式接口

作者头像
眯眯眼的猫头鹰
发布2019-10-15 10:37:05
5040
发布2019-10-15 10:37:05
举报
文章被收录于专栏:眯眯眼猫头鹰的小树杈

前情提要

看此文前,不熟悉函数式编程和Lambda表达式的可以先看一下上文回忆一下。

本文将会简单介绍Java8中内置的一些函数式接口

回顾函数式接口

函数式接口就是只定义一个抽象方法的接口。在JAVA8以前,就有很多符合函数式接口定义的接口。

代码语言:javascript
复制
//比较器
public interface Comparator<T> {
    int compare(T o1, T o2);
}

//多线程接口
public interface Runnable{
    void run();
}

因为JAVA8中还引入了默认方法的概念,所以即使接口中有多个默认方法,只要接口之定义了一个抽象方法,就满足函数式接口的定义。

JAVA8中对这些可以定义为函数式接口的接口加了一个@FuncationalInterface注解。如果一个接口中定义了多个抽象方法,又添加了这个注解,则会在编译时抛出错误提示。

Consumer

代码语言:javascript
复制
package java.util.function;

import java.util.Objects;

@FunctionalInterface
public interface Consumer<T> {
   
    void accept(T var1);

    default Consumer<T> andThen(Consumer<? super T> var1) {
        Objects.requireNonNull(var1);
        return (var2) -> {
            this.accept(var2);
            var1.accept(var2);
        };
    }
}

这是JAVA8中对Consumer的定义,该函数式接口可以接收一个T类型的数据,并对该数据进行操作。JDK中一个典型的例子是forEach中对Consumer的使用,下面给出了ArrayList中的forEach源码。

代码语言:javascript
复制
  @Override
  public void forEach(Consumer<? super E> consumer) {
    checkNotNull(consumer);
    for (E e : array) {
      consumer.accept(e);
    }
  }

forEach的接口定义中传入了一个Consumer接口,并且调用Consumer的accept方法对数组中的每个元素进行处理。加入这是一个String数组,则可以使用如下的方式进行调用

代码语言:javascript
复制
list.forEach((String s) -> System.out::println);

在Consumer的接口定义中,还有一个andThen的默认方法,后面会再介绍一下这个默认方法。

因为Consumer这个接口使用了泛型,因此只能使用基础类型的封箱类型,如Integer,Long等。如果是对基础类型的元素进行处理,可能会出现大量的封箱拆箱的操作,造成性能损耗。为了解决这个问题,JAVA也提供了基础类型的对应的Consumer接口,如IntConsumer:

代码语言:javascript
复制
@FunctionalInterface
public interface IntConsumer {

    void accept(int value);

    
    default IntConsumer andThen(IntConsumer after) {
        Objects.requireNonNull(after);
        return (int t) -> { accept(t); after.accept(t); };
    }
}

Predicate

代码语言:javascript
复制
@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);
    }

    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

Predicate函数式接口定义了test抽象方法,它会对T对象执行判断逻辑,并返回布尔类型的判断接口。

还是以ArrayList中的一个使用场景为例。ArrayList中提供了一个removeIf方法,该方法传入了Predicate接口,并利用该接口判断是否要删除这个对象:

代码语言:javascript
复制
  public boolean removeIf(Predicate<? super E> filter) {
    checkNotNull(filter);

    E[] newArray = null;
    int newIndex = 0;
    for (int index = 0; index < array.length; ++index) {
      E e = array[index];

      //使用Predicate的test方法判断是否要删除该对象
      if (filter.test(e)) {
        if (newArray == null) {
          newArray = ArrayHelper.clone(array, 0, index);
          newIndex = index;
        }
      } else if (newArray != null) {
        newArray[newIndex++] = e;
      }
    }

    if (newArray == null) {
      return false;
    }
    array = newArray;
    return true;
  }

当然了,同Consumer一样,它也提供了很多可以传入基础类型的Predicate接口,如IntPredicate,DoublePredicate等

Function

代码语言:javascript
复制
@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;
    }
}

Function中定义了apply抽象方法,该抽象方法会接受一个T类型的对象,并转化为R类型的对象返回。使用方法和上面也没啥区别,这里就不具体赘述了。当然了,Function也为基础类型做了很多扩展,比如IntToDoubleFunction就可以将int转化为double型,还有ToDoubleFunction<T>则支持将T对象转化为double基础型。

复合Lambda表达式

复合Lambda表达式是指将多个同类型的Lambda表达式按照一定语法进行组合,生成新的Lambda表达式。以比较基础的Predicate作为例子。Predicate中有以下几个默认方法:and,negate,or,分别对应与,否定和或。

举个例子,现在有两个Predicate分别是判断订单的状态是否为已支付以及订单的实付金额是否大于100。两个Predicate如下:

代码语言:javascript
复制
Predicate<Order> p1 = (Order o) -> o.isPaid;
Predicate<Order> p2 = (Order o) -> o.actualFee > 100;

假如现在想要判断是已支付且实付金额大于100的订单,则新的Predicate可以通过上面两个Predicate组合生成,利用and默认方法:

代码语言:javascript
复制
Predicate<Order> p3 = p1.and(p2);
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前情提要
  • 回顾函数式接口
  • Consumer
  • Predicate
  • Function
  • 复合Lambda表达式
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档