Java函数式接口(Functional Interface)

简单介绍

函数式接口(Functional Interface)是Java 8对一类特殊类型的接口的称呼。 这类接口只定义了唯一的抽象方法的接口,并且使用@FunctionalInterface 进行注解。

在jdk8中,引入了一个新的包 java.util.function, 提了几种分类场景,使java 8 的函数式编程变得更加简便。

示例

要实现一个场景,业务的执行实现和任务链实现分开。
采用函数式编程进行抽象分离。
如下定义了任务链的逻辑。有三个点:
1、采用泛型定义业务数据类型
2、业务的链条规则采用函数式接口定义
3、业务的执行逻辑采用函数式接口定义。

/**
 * 任务链 接口
 * @author peter
 *
 * @param <T>
 */
public interface TaskChainExecutorIntf<T> {
	
	static Logger logger = LoggerFactory.getLogger(TaskChainExecutorIntf.class);
	
	/**
	 * 任务链处理  
	 * 
	 * @param consumer
	 * @param map
	 */
	default void handleAsyncForTaskChain(T t, Function<T, String> functionNext, Consumer<T> consumer,
			Map<String, T> map) {
		logger.debug("..........handleAsyncForTaskChain print all map task: {}", JSON.toJSONString(map));
		consumer.accept(t);
		String tempNextName = functionNext.apply(t);
		T temp = null;
		// 链条下一个任务名 不为空 继续执行
		while(!StringUtils.isEmpty(tempNextName)) {
			temp = map.get(tempNextName);
			if(null == temp) {
				logger.error("..........handleAsyncForTaskChain next task error! can not find next task, task name: {}", tempNextName);
				break;
			}
			
			logger.debug("..........handleAsyncForTaskChain next task get success!, task name: {}", tempNextName);
			consumer.accept(temp);
			// 重新赋值
			tempNextName = functionNext.apply(temp);
		}
	}

	/**
	 * 非任务链处理
	 * 
	 * @param consumer
	 * @param map
	 */
	default void handleAsync(T t, Consumer<T> consumer) {
		consumer.accept(t);
	}

}

以下是业务的执行和执行链的结合:

	/**
	 * 处理实现入口
	 */
	public void process() {
		List<ETLDO> list = taskLoader.loadETLTask(YamlConfig.get(sqlMainName).toString(), defaultDataSource, 1, 10);
		logger.debug("..........list value :{}", JSON.toJSONString(list));
		
		// 任务链 处理
		//TaskChainHandler<ETLDO> chainHandler = new TaskChainHandler<ETLDO>(list);
		TaskChainHandler<ETLDO> chainHandler = TaskChainHandler.create(list, chainExecutor);
		chainHandler.handler(t -> {
			return t.getNext();
		}, t -> t.getName(), o -> {
			Map<String, Object> etldoMap = new HashMap<String, Object>();
			etldoMap = JSON.parseObject(JSON.toJSONString(o), Map.class);
			
			SqlDO sqlDO = SqlParseHelper.parse(YamlConfig.get(sqlMainLock).toString(), etldoMap);
			if(lockHandler.lockUnlock(sqlDO.getSql(), sqlDO.getObjArr(), dataSourceContext.getDefaultJdbcTemplate())) {
				logger.info("..........ETLDO task lock success! name :{}", o.getName());
				handle(o, etldoMap);
			}else {
				logger.info("..........ETLDO task lock failed, name :{}", o.getName());
			}
		});

可以看出来,只关注业务的逻辑实现和链条规则,至于怎么串联执行的,通过lambda表达式方式,交给任务链抽闲实现来做。
以上用了java.util.Function包下两个函数接口Function和Consumer。源码如下:


package java.util.function;

import java.util.Objects;

/**
 * Represents a function that accepts one argument and produces a result.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #apply(Object)}.
 *
 * @param <T> the type of the input to the function
 * @param <R> the type of the result of the function
 *
 * @since 1.8
 */
@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;
    }
}

package java.util.function;

import java.util.Objects;

/**
 * Represents an operation that accepts a single input argument and returns no
 * result. Unlike most other functional interfaces, {@code Consumer} is expected
 * to operate via side-effects.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #accept(Object)}.
 *
 * @param <T> the type of the input to the operation
 *
 * @since 1.8
 */
@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); };
    }
}

函数式接口的参数可以为函数式接口类型
入定义两个函数式接口:

@FunctionalInterface
public interface IFunc {
	
	String doSay(IFunc2 i);

}
@FunctionalInterface
public interface IFunc2 {
	
	String doSay();


}

其中接口IFunc中的方法参数 类型为 接口IFunc2
执行测试代码:

public class Test {
	
	public static void test(IFunc f, IFunc2 f2) {
		f.doSay(f2);
	}
	
	public static void test2(IFunc f) {
		IFunc2 f2 = () -> {System.out.println("this is func2"); return "2";};
		f.doSay(f2);
	}
	
	public static void test3(IFunc f) {
		f.doSay(() -> {System.out.println("this is func2 test3"); return "2";});
	}
	
	public static void main(String[] args) {
		test((a) -> { 
			System.out.println("this is func1");
			a.doSay();
			return "1";}, () -> {System.out.println("this is func2"); return "2";});
		
		test2((a) -> { 
			System.out.println("this is func1");
			a.doSay();
			return "1";});
		
		test3((a) -> { 
			System.out.println("this is func1");
			a.doSay();
			return "1";});
	}

}
this is func1
this is func2
this is func1
this is func2
this is func1
this is func2 test3

在这里插入图片描述
需要注意,当中的a只是引用。

java标准function

在java.util.function package下,大致分为四类:

  • Function: 接收参数,并返回结果,主要方法 R apply(T t)
    UnaryOperation 接收与返回类型相同,主要方法 T apply(T t)
    BiFunction 接收两个参数,并返回结果,主要方法 R apply(T t, U u)
    BinaryOperation 接收的两个参数与返回类型均相同,主要方法 T apply(T t, T u)

  • Consumer: 接收参数,无返回结果,主要方法 void accept(T t)
    BiConsumer 接收两个参数,无返回结果,主要方法 void accept(T t, U u)

  • Supplier: 不接收参数,但返回结构,主要方法 T get()

  • Predicate: 接收参数,返回boolean值,主要方法 boolean test(T t)
    BiPredicate 接收两个参数,返回boolean值,主要方法 boolean test(T t, U u)

如下图:
在这里插入图片描述

总结

函数式编程,简洁优美,缩短了抽象与实现的路径。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值