Lambda 表达式遍历集合的原理
在 Java 中,使用 Lambda 表达式遍历 List
和 Set
集合可以通过 forEach
方法实现,该方法接受一个 Consumer
函数式接口作为参数。以下是详细的说明和示例:
一、Lambda 表达式遍历集合的原理
Iterable.forEach()
方法
List
和Set
均实现了Iterable
接口,该接口定义了forEach(Consumer<? super T> action)
方法。Consumer
函数式接口
该接口的accept(T t)
方法定义了如何处理每个元素,可以用 Lambda 表达式简化实现。
二、遍历 List 集合
示例代码
import java.util.Arrays;
import java.util.List;public class ListTraversal {public static void main(String[] args) {List<String> list = Arrays.asList("Apple", "Banana", "Cherry");// 1. 使用 Lambda 表达式遍历list.forEach(item -> System.out.println(item));// 2. 使用方法引用简化list.forEach(System.out::println);}
}
public class LambdaTest38 {public static void main(String[] args) {//list集合List<Integer> list = Arrays.asList(1,2,3,4,56,5,6,0);//forEach方法的参数是一个函数式接口:Consumer(消费型接口)//使用匿名内部类list.forEach(new Consumer<Integer>(){@Overridepublic void accept(Integer elt) {System.out.println(elt);}});//使用lambda表达式list.forEach(elt-> System.out.println(elt));//使用实例方法引用精简,System.out相当于一个对象list.forEach(System.out::println);}
}
代码解析
list.forEach(item -> System.out.println(item))
Lambda 表达式直接对每个元素item
执行打印操作。list.forEach(System.out::println)
通过方法引用进一步简化代码,效果与 Lambda 表达式相同。
三、遍历 Set 集合
示例代码
import java.util.HashSet;
import java.util.Set;public class SetTraversal {public static void main(String[] args) {Set<String> set = new HashSet<>();set.add("Dog");set.add("Cat");set.add("Rabbit");// 1. 使用 Lambda 表达式遍历set.forEach(item -> System.out.println(item));// 2. 使用方法引用简化set.forEach(System.out::println);}
}
代码解析
- Set 的遍历方式与 List 完全一致,因为二者均继承自
Iterable
。
四、与传统遍历方式对比
传统 for 循环
// 遍历 List
for (String item : list) {System.out.println(item);
}// 遍历 Set
for (String item : set) {System.out.println(item);
}
迭代器 (Iterator)
// 遍历 List
Iterator<String> listIterator = list.iterator();
while (listIterator.hasNext()) {System.out.println(listIterator.next());
}// 遍历 Set
Iterator<String> setIterator = set.iterator();
while (setIterator.hasNext()) {System.out.println(setIterator.next());
}
Lambda 表达式的优势
- 代码简洁:减少模板代码(如循环变量、迭代器声明)。
- 可读性强:直接表达“对每个元素执行某操作”的意图。
- 函数式风格:易于结合 Stream API 进行链式操作(如过滤、映射)。
五、结合 Stream API 的复杂遍历
Lambda 表达式可与 Stream API 结合,实现更复杂的遍历逻辑。
示例:过滤并遍历
import java.util.Arrays;
import java.util.List;public class FilteredTraversal {public static void main(String[] args) {List<String> list = Arrays.asList("Apple", "Banana", "Cherry", "Date");// 过滤长度大于 5 的元素并遍历list.stream().filter(item -> item.length() > 5).forEach(System.out::println);// 输出: Banana, Cherry}
}
示例:映射并遍历
import java.util.Set;
import java.util.HashSet;public class MappedTraversal {public static void main(String[] args) {Set<Integer> numbers = new HashSet<>(Arrays.asList(1, 2, 3));// 将每个数字平方后遍历numbers.stream().map(n -> n * n).forEach(System.out::println);// 输出: 1, 4, 9}
}
六、注意事项
-
修改集合元素
在 Lambda 中直接修改集合(如删除元素)会导致ConcurrentModificationException
。
解决方案:使用迭代器的remove()
方法或 Stream API 的filter
。 -
访问外部变量
Lambda 表达式内访问的局部变量需为final
或等效final
。 -
性能考量
forEach
在简单遍历时性能与传统循环相当,但在复杂链式操作(如 Stream)中可能有额外开销。
七、总结
-
语法形式
list.forEach(item -> { /* 操作 */ }); set.forEach(item -> { /* 操作 */ });
-
适用场景
- 简单遍历集合元素。
- 结合 Stream API 进行过滤、映射等操作。
- 需要函数式编程风格的代码。
-
与传统方式对比
特性 Lambda + forEach 传统 for/Iterator 代码简洁性 高 低 可读性 高(声明式) 中(命令式) 功能性 支持链式操作(如Stream API) 需手动实现复杂逻辑