深入浅出Java函数式接口

  • 什么是函数式接口
  • 白话定义
  • 典型函数式接口
  • Supplier 供给型接口
  • Consumer 消费型接口
  • Function 函数式接口
  • Predicate 断言型接口
  • 活学活用


什么是函数式接口

白话定义

首先,什么是函数式接口?
有且仅有一个抽象方法的接口(可以包含其它默认,静态,私有方法)
Java中的函数式编程表现形式就是Lambda表达式,所以函数式接口就是可以使用Lambda的接口。保证只有一个抽象方法,就是为了Lambda表达式能够顺利进行推导。
函数式接口通常标注@FunctionalInterface注解,用以检查是否符合函数式接口规范,但不标注该注解,也可以是函数式接口。
有网友这样形容Java函数式接口,个人觉得特别形象准确,Java函数式接口类似于C++里的函数指针

典型函数式接口

Supplier 供给型接口

指定返回参数类型T,且无入参的方法

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

common-lang3包中org.apache.commons.lang3.ObjectUtils中有使用到该接口

* <p>
     * Returns the given {@code object} is it is non-null, otherwise returns the Supplier's {@link Supplier#get()}
     * value.
     * </p>
     *
     * <p>
     * The caller responsible for thread-safety and exception handling of default value supplier.
     * </p>
     *
     * <pre>
     * ObjectUtils.getIfNull(null, () -> null)     = null
     * ObjectUtils.getIfNull(null, null)              = null
     * ObjectUtils.getIfNull(null, () -> "")       = ""
     * ObjectUtils.getIfNull(null, () -> "zz")     = "zz"
     * ObjectUtils.getIfNull("abc", *)                = "abc"
     * ObjectUtils.getIfNull(Boolean.TRUE, *)         = Boolean.TRUE
     * </pre>
     *
     * @param <T> the type of the object
     * @param object the {@code Object} to test, may be {@code null}
     * @param defaultSupplier the default value to return, may be {@code null}
     * @return {@code object} if it is not {@code null}, {@code defaultValueSupplier.get()} otherwise
     * @since 3.10
     */
    public static <T> T getIfNull(final T object, final Supplier<T> defaultSupplier) {
        return object != null ? object : defaultSupplier == null ? null : defaultSupplier.get();
    } ```如果object为空且defaultSupplier不为空时,会根据defaultSupplier获取对应的输出。 当然,还有很多其它地方有使用到该接口的,自己可以去慢慢看。但该接口和Predicate确实没有另外两个用处广泛。

Consumer 消费型接口

指定一个入参类型T,且无返回参数的方法

@FunctionalInterface
public interface Consumer<T> {

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

    /**
     * Returns a composed {@code Consumer} that performs, in sequence, this
     * operation followed by the {@code after} operation. If performing either
     * operation throws an exception, it is relayed to the caller of the
     * composed operation.  If performing this operation throws an exception,
     * the {@code after} operation will not be performed.
     *
     * @param after the operation to perform after this operation
     * @return a composed {@code Consumer} that performs in sequence this
     * operation followed by the {@code after} operation
     * @throws NullPointerException if {@code after} is null
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

找了一个大家耳熟能详的,java.lang.Iterable中的forEach

default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } } ```大家应该有经常用这个方法来遍历List吧,不做过多赘述了。

Function 函数式接口

指定一个入参类型T,且返回指定类型R

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

    /**
     * Returns a composed function that first applies the {@code before}
     * function to its input, and then applies this function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of input to the {@code before} function, and to the
     *           composed function
     * @param before the function to apply before this function is applied
     * @return a composed function that first applies the {@code before}
     * function and then applies this function
     * @throws NullPointerException if before is null
     *
     * @see #andThen(Function)
     */
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    /**
     * Returns a composed function that first applies this function to
     * its input, and then applies the {@code after} function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of output of the {@code after} function, and of the
     *           composed function
     * @param after the function to apply after this function is applied
     * @return a composed function that first applies this function and then
     * applies the {@code after} function
     * @throws NullPointerException if after is null
     *
     * @see #compose(Function)
     */
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    /**
     * Returns a function that always returns its input argument.
     *
     * @param <T> the type of the input and output objects to the function
     * @return a function that always returns its input argument
     */
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

在hutool中找了个典型的用法,cn.hutool.core.convert.impl.NumberConverter

转换失败不会报错 	 * 	 * @param value     被转换的值 	 * @param toStrFunc
转换为字符串的函数规则 	 * @return 结果 	 */ 	private static BigDecimal
toBigDecimal(Object value, Function<Object, String> toStrFunc) { 		if
(value instanceof Number) { 			return NumberUtil.toBigDecimal((Number)
value); 		} else if (value instanceof Boolean) { 			return new
BigDecimal((boolean) value ? 1 : 0); 		} else if (value instanceof
byte[]){ 			return
NumberUtil.toBigDecimal(ByteUtil.bytesToDouble((byte[]) value)); 		}

		//对于Double类型,先要转换为String,避免精度问题 		return
NumberUtil.toBigDecimal(toStrFunc.apply(value)); 	} ```
转换逻辑写的比较友好,如果输入value是可以直接转换成数值,那就直接通过对应的方法转换,如果非纯数值,或自定义对象类型,可以通过自定义的函数进行处理。

Predicate 断言型接口

指定一个入参类型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);

    /**
     * Returns a composed predicate that represents a short-circuiting logical
     * AND of this predicate and another.  When evaluating the composed
     * predicate, if this predicate is {@code false}, then the {@code other}
     * predicate is not evaluated.
     *
     * <p>Any exceptions thrown during evaluation of either predicate are relayed
     * to the caller; if evaluation of this predicate throws an exception, the
     * {@code other} predicate will not be evaluated.
     *
     * @param other a predicate that will be logically-ANDed with this
     *              predicate
     * @return a composed predicate that represents the short-circuiting logical
     * AND of this predicate and the {@code other} predicate
     * @throws NullPointerException if other is null
     */
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

    /**
     * Returns a predicate that represents the logical negation of this
     * predicate.
     *
     * @return a predicate that represents the logical negation of this
     * predicate
     */
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    /**
     * Returns a composed predicate that represents a short-circuiting logical
     * OR of this predicate and another.  When evaluating the composed
     * predicate, if this predicate is {@code true}, then the {@code other}
     * predicate is not evaluated.
     *
     * <p>Any exceptions thrown during evaluation of either predicate are relayed
     * to the caller; if evaluation of this predicate throws an exception, the
     * {@code other} predicate will not be evaluated.
     *
     * @param other a predicate that will be logically-ORed with this
     *              predicate
     * @return a composed predicate that represents the short-circuiting logical
     * OR of this predicate and the {@code other} predicate
     * @throws NullPointerException if other is null
     */
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

    /**
     * Returns a predicate that tests if two arguments are equal according
     * to {@link Objects#equals(Object, Object)}.
     *
     * @param <T> the type of arguments to the predicate
     * @param targetRef the object reference with which to compare for equality,
     *               which may be {@code null}
     * @return a predicate that tests if two arguments are equal according
     * to {@link Objects#equals(Object, Object)}
     */
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

java.util.Vector中的removeIf有用词做判断

@SuppressWarnings("unchecked")
    public synchronized boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        // figure out which elements are to be removed
        // any exception thrown from the filter predicate at this stage
        // will leave the collection unmodified
        int removeCount = 0;
        final int size = elementCount;
        final BitSet removeSet = new BitSet(size);
        final int expectedModCount = modCount;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            @SuppressWarnings("unchecked")
            final E element = (E) elementData[i];
            if (filter.test(element)) {
                removeSet.set(i);
                removeCount++;
            }
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }

        // shift surviving elements left over the spaces left by removed elements
        final boolean anyToRemove = removeCount > 0;
        if (anyToRemove) {
            final int newSize = size - removeCount;
            for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
                i = removeSet.nextClearBit(i);
                elementData[j] = elementData[i];
            }
            for (int k=newSize; k < size; k++) {
                elementData[k] = null;  // Let gc do its work
            }
            elementCount = newSize;
            if (modCount != expectedModCount) {
                throw new ConcurrentModificationException();
            }
            modCount++;
        }

        return anyToRemove;
    } ```

活学活用

先定义一个基础bean

@Data
public class BaseEntity {
    @ApiModelProperty(value = "主键")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    @ApiModelProperty(value = "创建日期")
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createDate;

    @ApiModelProperty(value = "更新日期")
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateDate;

    @ApiModelProperty(value = "是否删除,0未删除,1已删除")
    private Boolean isDelete;

    @ApiModelProperty(value = "是否有效,0无效,1有效")
    private Integer effectFlag;

    @ApiModelProperty(value = "版本号")
    private Integer versionNum;

    @ApiModelProperty(value = "创建人")
    private Long createBy;

    @ApiModelProperty(value = "更新人")
    private Long updateBy;
}

再来个helper测试一下各个函数式接口的效果

@Slf4j
public class BaseEntityHelper {
    public static Supplier<BaseEntity> supplier = BaseEntity::new;


    public static void consumer(BaseEntity entity, Consumer<BaseEntity> consumer) {
        consumer.accept(entity);
    }

    public static BaseEntity function(Function<BaseEntity, BaseEntity> function) {
        return function.apply(supplier.get());
    }

    public static Boolean predicate(BaseEntity entity, Predicate<BaseEntity> predicate) {
        return predicate.test(entity);
    }

    public static void main(String[] args) {
        // supplier
        BaseEntity entity = supplier.get();
        log.info(entity.toString());
        // consume
        consumer(entity, v -> {
            v.setVersionNum(1);
        });
        log.info(entity.toString());
        // function
        entity = function(v -> {
            v.setIsDelete(Boolean.FALSE);
            return v;
        });
        log.info(entity.toString());
        // predicate
        Boolean predicate = predicate(entity, BaseEntity::getIsDelete);
        log.info(BooleanUtil.toStringTrueFalse(predicate));
    }
}

运行结果

16:54:15.341 [main] INFO com.roswu.helper.infras.helper.BaseEntityHelper - BaseEntity(id=null, createDate=null, updateDate=null, isDelete=null, effectFlag=null, versionNum=null, createBy=null, updateBy=null)
16:54:15.344 [main] INFO com.roswu.helper.infras.helper.BaseEntityHelper - BaseEntity(id=null, createDate=null, updateDate=null, isDelete=null, effectFlag=null, versionNum=1, createBy=null, updateBy=null)
16:54:15.345 [main] INFO com.roswu.helper.infras.helper.BaseEntityHelper - BaseEntity(id=null, createDate=null, updateDate=null, isDelete=false, effectFlag=null, versionNum=null, createBy=null, updateBy=null)
16:54:15.350 [main] INFO com.roswu.helper.infras.helper.BaseEntityHelper - false