一、函数式接口
函数式接口定义且只定义了一个抽象方法,函数式接口很有用,因为抽象方法的签名可以描述Lambda表达式的签名。
函数式接口示例
- Predicate
接口定义了一个 test 抽象方法,接收一个泛型T,并返回一个布尔型。
// lambda 表达式 filter 过滤器的操作就是通过 Predicate 函数式接口实现的
list.stream().filter(f -> "value".equal(f.value) )- Consumer
接口定义了一个 accept 抽象方法,接收泛型T对象,没有返回, ,例如
pulic static void main(String[] args) {
        // 案例 1, 对入参进行消费,没有返回值
	Consumer<Integer> consumer = x -> {
		int a = x + 2;
		System.out.println(a);// 12
		System.out.println(a + "_");// 12_
	};
	consumer.accept(10);
        // 案例2,
	List<String> list = new ArrayList<>();
	list.forEach(item -> {
		System.out.println(item);
	});
}
- Function
接口定义了一个 apply 方法,它接受一个泛型 T 对象返回一个 泛型 R对象。
Function 方法还有很多类型
| Function<T,R> | 接收一个参数并返回结果的函数 | 
|---|---|
| BiFunction<T,U,R> | 接受两个参数并返回结果的函数 | 
| DoubleFunction | 接收一个double类型的参数并返回结果的函数 | 
| DoubleToIntFunction | 接收一个double类型的参数并返回int结果的函数 | 
| DoubleToLongFunction | 接收一个double类型的参数并返回long结果的函数 | 
| IntFunction | 接收一个int类型的参数并返回结果的函数 | 
| IntToDoubleFunction | 接收一个int类型的参数并返回double结果的函数 | 
| IntToLongFunction | 接收一个int类型的参数并返回long结果的函数 | 
| LongFunction | 接收一个long类型的参数并返回结果的函数 | 
| LongToDoubleFunction | 接收一个long类型的参数并返回double结果的函数 | 
| LongToIntFunction | 接收一个long类型的参数并返回int结果的函数 | 
| ToDoubleBiFunction<T,U> | 接收两个参数并返回double结果的函数 | 
| ToDoubleFunction | 接收一个参数并返回double结果的函数 | 
| ToIntBiFunction<T,U> | 接收两个参数并返回int结果的函数 | 
| ToIntFunction | 接收一个参数并返回int结果的函数 | 
| ToLongBiFunction<T,U> | 接收两个参数并返回long结果的函数 | 
| ToLongFunction | 接收一个参数并返回long结果的函数 | 
public class Transaction {
	/**
	 * 年
	 */
	private final int year;
        public int getYear() {
		return year;
	}
}
public static void main(String[] args) {
        // 在此案例中map 接口接收了一个 Transaction 类, 返回了 int 类的 year。
        List<String> cities = transactions.stream()
		.map(transaction -> transaction.getYear())
		.distinct()
		.collect(toList());
}
如何自定义函数式接口?
函数式接口定义且只定义了一个抽象方法。并在接口上使用函数式接口注解 @FunctionalInterface,此注解作用:主要用于校验此函数式接口是否合法(校验此函数式接口类中是否只有一个抽象方法)。
// 案例一 :无参函数式接口
/**
 * 自定义函数式接口
 * 有且只有一个抽象方法
 *
 * 执行任务
 */
@FunctionalInterface
public interface JobFunction {
	abstract void execute();
	// 静态方法
	static void test1() {
		System.out.println("1");
	}
	// 默认方法
	default void test2() {
		System.out.println("2");
	}
	// 所有的类都继承于 Object 的方法 equals
	public boolean equals(Object var1);
}    
public static void main(String[] args) {
	// 第一种写法
	JobFunction jobFunction = new JobFunction() {
		@Override
		public void execute() {
			System.out.println("testFunction1");
		}
	};
	// 第二种写法
	JobFunction jobFunction2 = () -> System.out.println("testFunction2");
	jobFunction.execute();
	jobFunction2.execute();
}	    
// 案例二 :指定类型函数式接口
@FunctionalInterface
public interface TestFunctionInterfaceSpecType {
	String test(Integer t1, Integer t2);
}
public static void main(String[] args) {
	// 案例二:指定参数函数式接口
	TestFunctionInterfaceSpecType testFunctionInterface2 = new TestFunctionInterfaceSpecType() {
		@Override
		public String test(Integer t1, Integer t2) {
			return "第一个参数为:" + t1 + "  第二个参数为:" + t2;
		}
	};
	System.out.println(
		testFunctionInterface2.test(1024, 1024*4 )
	);
}
// 案例三 :泛型函数式接口
@FunctionalInterface
public interface TestFunctionInterface<R, T>{
	R operator(T t1, T t2);
}
public class FunctionTest {
	public static void main(String[] args) {
		// 第一种写法
		TestFunctionInterface<String,Integer> testFunctionInterface = new TestFunctionInterface<String,Integer>(){
			@Override
			public String operator(Integer t1, Integer t2) {
				return t1.toString() + "、"+t2.toString();
			}
		};
		System.out.println(
				testFunctionInterface.operator(111,2222)
		);
		
		// 第二种写法,将函数式接口封装在方法中进行调用
		System.out.println(
				operator(1,2,(Integer a, Integer b) -> { return a+b;})
		);
	}
        // 函数式接口封装入方法中进行调用
	public static Integer operator(Integer a, Integer b, TestFunctionInterface<Integer, Integer> of) {
		return of.operator(a, b);
	}
}
总结:
函数式接口的使用技巧,
- 明确函数式接口的 函数描述符(也就是函数式接口的入参,及出参)
- 确定函数式接口使用范围,例如 Function 接口可是使用在类型转换(入参是一个类,出参是一个类), Predicate 接口可以使用在判定(因为入参是一个类,出参是boolean)
- 自定义函数式接口,记得要符合规范(有且只有一个抽象方法)
 
 
                            