本文概要
- 什么是函数式接口?
- 如何定义函数式接口?
- 常用的函数式接口
- 函数式接口语法注意事项
- 总结
1. 什么是函数式接口?
函数式接口其实本质上还是一个接口,但是它是一种特殊的接口:SAM类型的接口(Single Abstract Method),在这个接口里面只能有一个抽象方法。
当开发者在编写Lambda表达式时,也会随之被编译成一个函数式接口。Lambda表达式只是语法糖,我们只要理解函数式接口,才能读懂和用好Lambda表达式。
2. 如何定义函数式接口?
@FunctionalInterface
public interface FunctionDemo {
void get(String str);
}
FunctionDemo fd = str -> System.out.println("Hello " + str);
3. 常用的函数式接口
使用Lambda表达式,一定有函数式接口的支持;但是如果我们每一个Lambda表达式都要自己创建一个接口,
这样很造成很大的不便。为了避免重复造轮子,java8常用的函数式接口都帮我们定义好,拿来直接使用即可。
如果这些常用的接口不能满足需求时,这时才需要 自定义函数式接口。
下面是我们常用的几类函数式接口:
- 消费性函数式接口
特点:接受一个或者多个参数,没有返回值
- 供给型函数式接口
特点:没有参数(无参),提供返回值
- 函数型函数式接口
特点:接收一个或者多个参数,有返回值
- 断定性函数式接口
特点:接收一个或者多个参数,返回一个boolean类型
@Test
public void testCoreInter(){
/**
* @name 消费型接口
* @use Consumer<T>
* @param T 传入参数
* @fun 接受一个参数 无返回值
* */
Consumer<String> con=(str)->System.out.println(str);
con.accept("我是消费型接口!");
/**
* @name 供给型接口
* @use Supplier<R>
* @param R 返回值类型
* @fun 无参数 有返回值
* */
Supplier<Date> supp=()-> new Date();
Date date=supp.get();
System.out.println("当前时间:"+date);
/**
* @name 函数型接口
* @use Function<T,R>
* @param T 传入参数
* @return R 返回值类型
* @fun 接受一个参数 有返回值
* */
Function<String, String> fun=(str)->"hello,"+str;
String str=fun.apply("张俊强");
System.out.println(str);
/**
* @name 断定型接口
* @use Predicate<T>
* @param T 传入参数
* @return Boolean 返回一个Boolean型值
* @fun 接受一个参数 返回Boolean型值
* */
Predicate<Integer> pre=(num)->num>0;
Boolean flag=pre.test(10);
System.out.println(flag);
}
比如方法foreach(),入参为Consumer
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
4. 函数式接口语法注意事项
从SAM原则上讲,这个接口中,只能有一个函数需要被实现,但是也可以有如下例外:
- 默认方法:必须用default修饰,且只能是public,默认也是public。
它也是作为一种向后兼容能力而出现,旧的接口也能用到Lambda表达式中。例如,List或Collection接口是没有forEach方法的声明的。Java 8引入默认方式使得List和Collection接口能够拥有forEach方法的默认实现。实现了这些接口的类也不必再实现相同的功能了。
语法如下所示:
@FunctionalInterface
interface A {
default void test() {
System.out.println("接口A的默认方法");
}
void test1();
}
- 静态方法
函数式接口中可以有静态方法,一个或者多个静态方法不会影响SAM接口成为函数式接口,并且静态方法可以提供方法实现
@FunctionalInterface
interface TestStaticMethod {
//这是一个抽象方法
void test();
//静态方法,不是抽象方法
static void test1() {
System.out.println("接口里的静态方法!");
}
}
- 如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。
If an interface declares an abstract method overriding one of the public methods of {@code java.lang.Object},
that also doesnot count toward the interface's abstract method count
since any implementation of the interface will have an implementation from {@code java.lang.Object} or elsewhere.
@FunctionalInterface
public interface DemoFunctionalInterface{
void action();
//Object's public methods
String toString();
int hashCode();
boolean equals(Object o);
}
- 注解@FunctionalInterface不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错
5. 总结
- 函数式接口只能包含一个抽象方法
- 函数式接口可以包含Object类中所有public修饰的方法
- 函数工接口可以包含一个或多个静态方或默认方法
参考文献
- Java8 新特性----函数式接口,以及和Lambda表达式的关系
- Java8新特性(内置的核心函数式接口)
- Java8的四大核心函数式接口
- java8新特性之函数式接口、lambda表达式、接口的默认方法、方法和构造函数的引用
- java 8 新特性(1.函数式接口 - Functional Interface
- java8 函数式接口(FunctionalInterface) [一]
tips:本文属于自己学习和实践过程的记录,很多图和文字都粘贴自网上文章,没有注明引用请包涵!如有任何问题请留言或邮件通知,我会及时回复。