这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战
前言
函数式接口@FunctionalInterface,我们看一些JUC底层源码的时候很多就用到函数式接口@FunctionalInterface, 了解一下对源码还是很有帮助的。
JDK1.8 函数式接口特点:
1、该注解只能标记在”有且仅有一个抽象方法”的接口上。
2、JDK8接口中的静态方法和默认方法,都不算是抽象方法。
3、接口默认继承Java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。
4、该注解不是必须的,如果一个接口符合”函数式接口”定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。
应用
@FunctionalInterface
public interface FunService {
void say(String msg);
}
public class FunTest {
public static void main(String[] args) {
String msg = "hello";
FunService funService = msg1 -> {
System.out.println(msg);
};
funService.say(msg);
funService.say(msg);
funService.say(msg);
}
}
什么是函数式接口(Functional Interface)
其实之前在讲Lambda表达式的时候提到过,所谓的函数式接口,当然首先是一个接口,然后就是在这个接口里面只能有一个抽象方法。
这种类型的接口也称为SAM接口,即Single Abstract Method interfaces。
函数式接口用途
它们主要用在Lambda表达式和方法引用(实际上也可认为是Lambda表达式)上。
常见的lambda表达式
public class FunTest {
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
User user = new User();
user.setId(1L);
user.setAge(18);
user.setName("小明");
userList.add(user);
User user1 = new User();
user1.setId(2L);
user1.setAge(19);
user1.setName("小张");
userList.add(user1);
User user2 = new User();
user2.setId(3L);
user2.setAge(17);
user2.setName("小小");
userList.add(user2);
// 对象转换为map
Map<Long, User> map = userList.stream().collect(Collectors.toMap(User::getId, account -> account));
System.out.println(JSON.toJSONString(map));
// 获取ids 去重
Set<Long> ids = userList.stream().map(User::getId).collect(Collectors.toSet());
System.out.println(ids);
// 条件过滤
List<User> list = userList.stream().filter(e -> e.getAge() > 17L).collect(Collectors.toList());
System.out.println(JSON.toJSONString(list));
}
}
JDK中的函数式接口举例
java.lang.Runnable,
java.awt.event.ActionListener,
java.util.Comparator,
java.util.concurrent.Callable
java.util.function包下的接口,如Consumer、Predicate、Supplier等
当然比如常见的工具类Hutool中也大量应用了函数式接口, 各有利弊,函数式接口可以使代码更加简洁,但是用不好或者没有相关的知识就比较晦涩难懂。