深入浅出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