掌握 Java Lambda 表达式:从基础到 Stream API 实战
掌握 Java Lambda 表达式
探索 Java Lambda 表达式、函数式接口、泛型与 Stream API,配清晰示例。
Java 8 引入 Lambda 表达式增强语言表达力,让开发者编写更简洁可读的代码。
深入前需理解函数式接口——Lambda 实现的基石。
什么是函数式接口?
函数式接口是仅包含一个抽象方法的 Java 接口。该单一方法定义接口用途。
java.lang 的 Runnable 是经典例子,仅暴露 run() 方法。
示例 1:定义函数式接口
import java.lang.FunctionalInterface;
@FunctionalInterface
public interface MyInterface {
// 单一抽象方法
double getValue();
}
@FunctionalInterface 注解强制编译器遵守函数式接口契约,防止意外添加多个抽象方法。注解可选但强烈推荐以提高清晰度和安全性。
Java 7 中函数式接口称为单一抽象方法(SAM),通常用匿名类实现。
示例 2:用匿名类实现 SAM
public class FunctionInterfaceTest {
public static void main(String[] args) {
// 匿名类实现 Runnable
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("I just implemented the Runnable Functional Interface.");
}
}).start();
}
}
输出:
I just implemented the Runnable Functional Interface.
匿名类虽比传统实现减少样板代码,但语法仍冗长。Lambda 表达式消除传递函数式接口为参数时的显式方法名。
Lambda 表达式简介
Lambda 表达式本质是匿名方法,为函数式接口的抽象方法提供简洁实现。不独立执行,而是为接口方法提供行为。
如何在 Java 中定义 Lambda 表达式
通用语法:
(parameter list) -> lambda body
箭头操作符(->)分隔参数列表与主体。具体示例如下。
假设有返回 Pi 的方法:
double getPiValue() { return 3.1415; }
用 Lambda:
() -> 3.1415
无参数时箭头左侧为空,右侧为返回值的表达式主体。
Lambda 主体类型
Java Lambda 主体有两种形式:
1. 表达式主体 – 含单一表达式。
() -> System.out.println("Lambdas are great");
2. 代码块主体 – 用大括号包裹,允许多语句和可选 return。
() -> { double pi = 3.1415; return pi; };
注意:表达式主体不需显式 return,代码块主体若返回值则需 return。
示例 3:Lambda 表达式实战
编写程序用 Lambda 返回 Pi:
import java.lang.FunctionalInterface;
@FunctionalInterface
interface MyInterface {
double getPiValue();
}
public class Main {
public static void main(String[] args) {
MyInterface ref = () -> 3.1415;
System.out.println("Value of Pi = " + ref.getPiValue());
}
}
输出:
Value of Pi = 3.1415
要点:
MyInterface定义单一抽象方法- 声明
MyInterface引用但不直接实例化 - Lambda 表达式为
getPiValue()提供实现 - 调用
ref.getPiValue()触发 Lambda 主体
带参数的 Lambda 表达式
Lambda 可接受参数,如方法。示例:
(n) -> (n % 2) == 0
此 Lambda 判断输入整数是否为偶数。
示例 4:用参数化 Lambda 反转字符串
@FunctionalInterface
interface MyInterface {
String reverse(String s);
}
public class Main {
public static void main(String[] args) {
MyInterface ref = (str) -> {
String result = "";
for (int i = str.length() - 1; i >= 0; i--) {
result += str.charAt(i);
}
return result;
};
System.out.println("Lambda reversed = " + ref.reverse("Lambda"));
}
}
输出:
Lambda reversed = adbmaL
泛型函数式接口
函数式接口可为泛型,操作任意数据类型。例如:
@FunctionalInterface
interface MyInterface {
T func(T t);
}
示例 5:字符串与整数的泛型 Lambda
public class Main {
public static void main(String[] args) {
// 字符串反转
MyInterface reverse = (str) -> {
String result = "";
for (int i = str.length() - 1; i >= 0; i--) {
result += str.charAt(i);
}
return result;
};
System.out.println("Lambda reversed = " + reverse.func("Lambda"));
// 整数阶乘
MyInterface factorial = (n) -> {
int result = 1;
for (int i = 1; i <= n; i++) {
result *= i;
}
return result;
};
System.out.println("factorial of 5 = " + factorial.func(5));
}
}
输出:
Lambda reversed = adbmaL factorial of 5 = 120
Lambda 表达式与 Stream API
java.util.stream 包(JDK 8 引入)赋能开发者对集合执行函数式操作:过滤、映射、归约、排序等。
考虑地名列表,每个以国家为前缀。用流和 Lambda 高效提取操作数据。
示例 6:带 Lambda 的流处理
import java.util.ArrayList;
import java.util.List;
public class StreamMain {
static List places = new ArrayList<>();
public static List getPlaces() {
places.add("Nepa, Kathmandu");
places.add("Nepa, Pokhara");
places.add("India, Delhi");
places.add("USA, New York");
places.add("Africa, Nigeria");
return places;
}
public static void main(String[] args) {
List myPlaces = getPlaces();
System.out.println("Places from Nepal:");
myPlaces.stream()
.filter(p -> p.startsWith("Nepa"))
.map(p -> p.toUpperCase())
.sorted()
.forEach(p -> System.out.println(p));
}
}
输出:
Places from Nepal: NEPA, KATHMANDU NEPA, POKHARA
流操作链——filter、map、sorted、forEach——各接受 Lambda,相比 Java 8 前大幅减少样板代码。
java
- 掌握 C# 接口:定义、实现与实战场景全解析
- 精通 Java 运算符:类型、语法与实战示例
- 理解 Java 表达式、语句与代码块
- 精通 Java 接口:概念、实现与最佳实践
- 精通 Java Try-With-Resources:自动资源管理详解
- Java 注解详解:类型、放置位置与实战示例
- 掌握 Java NavigableSet 接口:导航、排序与实战示例
- Java 接口 vs 抽象类:如何选择合适的抽象方式
- Java 正则表达式完全指南:掌握 java.util.regex 模式匹配
- Java 接口全解析:定义契约、默认方法、多实现与标记接口
- Java 9 接口私有方法:增强封装与代码复用
- 精通 Java 8 Lambda 表达式:函数式编程入门指南