目录
问题一:首先,(在)java中什么是函数式接口?
Java中的函数式接口
定义
特点
常见内置函数式接口
自定义函数式接口示例
注意事项
问题二:Comparator接口为什么有compare和equals两个抽象方法,它还是一个函数式接口?
原因:equals 是 Object 类的方法
验证:@FunctionalInterface 注解
结论
问题:Comparator接口有compare和equals两个抽象方法,为什么它还是一个函数式接口?
背景:在使用和扩展学习“方法引用”时用到Comparator类下的compare方法,无意间点进源码看了下发现了这个问题,突然就有一种“物理学不存在了”的虚幻与现实相结合的奇妙感觉😂,是高司令开发Java时留的🐞bug吗?比较好奇,索性记录一下这个问题。
注意:本文部分片段引用了LLM的回答!有的地方总结的实在很好,所以一并粘贴出来。
问题一:首先,(在)java中什么是函数式接口?
Java中的函数式接口
函数式接口(Functional Interface)是Java 8引入的一个重要概念,它是Lambda表达式和方法引用的基础。
定义
函数式接口是指仅包含一个抽象方法的接口(可以包含多个默认方法或静态方法)。Java 8通过@FunctionalInterface
注解来显式标识一个接口是函数式接口。
特点
-
单一抽象方法:只能有一个抽象方法
-
可选注解:可以使用
@FunctionalInterface
注解标记(非必须,但推荐) -
兼容性:可以有多个默认方法或静态方法
-
继承:如果接口继承另一个接口且父接口已经是函数式接口,那么子接口仍然是函数式接口
常见内置函数式接口
Java 8在java.util.function
包中提供了许多常用的函数式接口:
-
Function<T, R>
- 接受一个输入参数T,返回结果RFunction<String, Integer> strToInt = s -> Integer.parseInt(s);
-
Predicate<T>
- 接受一个输入参数,返回boolean值Predicate<String> isLong = s -> s.length() > 10;
-
Consumer<T>
- 接受一个输入参数,无返回值Consumer<String> printer = s -> System.out.println(s);
-
Supplier<T>
- 无输入参数,返回一个结果Supplier<Double> random = () -> Math.random();
-
UnaryOperator<T>
- 接受一个参数T,返回相同类型T的结果(Function的特例)UnaryOperator<String> toUpper = s -> s.toUpperCase();
-
BiFunction<T, U, R>
- 接受两个参数T和U,返回结果RBiFunction<Integer, Integer, Integer> adder = (a, b) -> a + b;
自定义函数式接口示例
@FunctionalInterface
interface StringProcessor {String process(String input);// 可以有默认方法default void printInfo() {System.out.println("This is a string processor");}
}public class Main {public static void main(String[] args) {StringProcessor toUpper = s -> s.toUpperCase();System.out.println(toUpper.process("hello")); // 输出 "HELLO"}
}
注意事项
-
即使不使用
@FunctionalInterface
注解,只要接口符合函数式接口的定义,它仍然是函数式接口 -
注解的主要作用是让编译器检查接口是否符合函数式接口的定义
-
从Java 8开始,接口可以有默认方法实现,这不会影响函数式接口的定义
函数式接口是Java函数式编程的基础,它使得Lambda表达式能够以简洁的方式实现接口的单一抽象方法。
问题二:Comparator接口为什么有compare和equals两个抽象方法,它还是一个函数式接口?
确实,Comparator
接口看起来有两个抽象方法:compare(T o1, T o2)
和 equals(Object obj)
,但它仍然是一个函数式接口。为什么呢?👇
原因:equals
是 Object
类的方法
虽然 Comparator
接口声明了两个抽象方法:
-
int compare(T o1, T o2)
-
boolean equals(Object obj)
但实际上,equals
方法并不算作函数式接口的抽象方法,因为:
-
equals
是Object
类的方法,所有 Java 对象都继承自Object
,所以equals
方法已经有一个默认实现(除非被覆盖)。 -
Java 规范明确规定:如果接口声明了一个
Object
类中的公共方法(如equals
、toString
、hashCode
),它不会计入函数式接口的抽象方法数量。
因此,Comparator
实际上只有一个抽象方法 compare
,符合函数式接口的定义。
验证:@FunctionalInterface
注解
Comparator
被标记为 @FunctionalInterface
,如果它不符合函数式接口的定义,编译器会报错。例如:
@FunctionalInterface
public interface Comparator<T> {int compare(T o1, T o2); // 唯一的抽象方法(函数式接口的核心)boolean equals(Object obj); // 不算,因为它是 Object 的方法// 其他默认方法和静态方法...
}
如果尝试添加另一个抽象方法(非 Object
方法),编译器会报错:
@FunctionalInterface
interface InvalidComparator<T> {int compare(T o1, T o2);boolean equals(Object obj);void anotherMethod(); // 编译错误:InvalidComparator 不是函数式接口,因为它有多个抽象方法
}
结论
✅ Comparator
是函数式接口,因为它只有一个真正的抽象方法 compare
。
✅ equals
不算,因为它是 Object
的方法,不会影响函数式接口的定义。
✅ 这个规则适用于所有函数式接口,比如 Runnable
(仅 run()
)、Callable
(仅 call()
)等。
所以,Comparator
仍然可以用于 Lambda 表达式:
Comparator<String> lengthComparator = (s1, s2) -> s1.length() - s2.length();
工作快猝shi了,抽空发个帖子,结果弹出这么个玩意出来👇
你食不食油饼啊?😅
ps:(夹子音🔊)家人们,谁懂啊?csdn真好用呀!没有各种限制,没有盗文引流,编辑器简单好用易上手,真是太好了呢!~
朋友,如果你也这么认为,请给这篇文章点个大拇哥吧,(*^_^*)-_-!👍
补充:现在发布文章好像不能保存为草稿了。。。