Java,举例说明,函数式接口,函数式接口实现类,通过匿名内部类实现函数式接口,通过 Lambda 表达式实现函数式接口,演变的过程

1. 什么是函数式接口 (Functional Interface)?
函数式接口是 只包含一个抽象方法 的接口。它可以用 Lambda 表达式、方法引用或构造器引用进行实例化。
为了明确表示一个接口是函数式接口,通常使用 @FunctionalInterface 注解(非强制,但推荐)。
示例:定义一个简单的函数式接口
java
@FunctionalInterface
public interface GreetingService {
// 只有一个抽象方法
void greet(String name);
// 可以有默认方法和静态方法,不影响其作为函数式接口
default void sayGoodbye() {
System.out.println("Goodbye!");
}
}
2. 函数式接口的实现类
你可以像普通接口一样,创建一个具体的实现类来实现这个接口。
示例:通过普通类实现函数式接口
java
// 实现类
class EnglishGreeting implements GreetingService {
@Override
public void greet(String name) {
System.out.println("Hello, " + name);
}
}
// 使用
public class Main {
public static void main(String[] args) {
GreetingService service = new EnglishGreeting();
service.greet("Alice"); // 输出: Hello, Alice
}
}
这种方式虽然可行,但在需要传递简单行为逻辑的场景下显得繁琐。
3. 通过匿名内部类 (Anonymous Inner Class) 实现函数式接口
在 Lambda 表达式出现之前,如果需要在代码中直接提供接口的实现,最常用的方式就是匿名内部类。
示例:使用匿名内部类
java
public class Main {
public static void main(String[] args) {
// 创建一个匿名内部类来实现 GreetingService 接口
GreetingService service = new GreetingService() {
@Override
public void greet(String name) {
System.out.println("Hello from anonymous class, " + name);
}
};
service.greet("Bob"); // 输出: Hello from anonymous class, Bob
}
}
- 优点:可以在需要时就地创建实现,无需预先定义一个类。
- 缺点 :代码冗长,包含了很多样板代码(
new GreetingService() { ... }和@Override),可读性较差。
4. 通过 Lambda 表达式 (Lambda Expression) 实现函数式接口
Lambda 表达式是 Java 8 引入的语法糖,它为函数式接口提供了更简洁、更优雅的实现方式。它的核心思想是"把功能(行为)当作参数"传递。
语法 :(parameters) -> { body }
演变过程:
-
原始匿名内部类:
javaGreetingService service = new GreetingService() { @Override public void greet(String name) { System.out.println("Hello, " + name); } }; -
简化第一步:去掉外部结构
因为编译器知道
GreetingService是一个函数式接口,且只接受一个String参数,所以可以省略new GreetingService()、@Override和方法名。java// Lambda 表达式 GreetingService service = (String name) -> { System.out.println("Hello, " + name); }; -
简化第二步:类型推断
编译器可以从上下文 (
GreetingService接口的greet方法签名) 推断出name的类型是String,因此可以省略参数类型。javaGreetingService service = (name) -> { System.out.println("Hello, " + name); }; -
简化第三步:单个参数的括号
如果 Lambda 表达式只有一个参数,且类型已知,可以省略参数外的括号。
javaGreetingService service = name -> { System.out.println("Hello, " + name); }; -
简化第四步:单行表达式体
如果 Lambda 的主体只有一条语句,可以省略大括号
{}和return关键字(如果有返回值的话)。java// 最终形态 GreetingService service = name -> System.out.println("Hello, " + name);
完整示例:使用 Lambda 表达式
java
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
// 使用 Lambda 表达式创建实现
GreetingService service = name -> System.out.println("Hello, " + name);
service.greet("Charlie"); // 输出: Hello, Charlie
// --- Lambda 在实际应用中的强大之处 ---
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 将 Lambda 表达式作为参数传递给 forEach 方法
// forEach 方法接收一个 Consumer<T> 类型的函数式接口
names.forEach(name -> System.out.println(name));
// 上面这行代码等价于匿名内部类:
/*
names.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
*/
}
}
总结:演变的核心思想
这个演变过程体现了从面向对象编程 (OOP) 向函数式编程 (FP) 思想的融合。
- 传统 OOP 方式:必须先创建一个类,然后实例化该类的对象来执行特定行为。
- 匿名内部类 :简化了 OOP 的流程,在需要的地方直接定义行为,但仍带有 OOP 的痕迹(如
new,@Override)。 - Lambda 表达式 :彻底将行为本身(函数)作为第一等公民,直接传递给需要的地方,代码更加简洁、聚焦于"做什么"而非"如何做"。
这种演变极大地提高了代码的可读性和表达力,特别是在处理集合、事件监听等场景中。