一、函数式接口
函数式接口定义且只定义了一个抽象方法,函数式接口很有用,因为抽象方法的签名可以描述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)
- 自定义函数式接口,记得要符合规范(有且只有一个抽象方法)