可能对于很多人来说,Lambda 显得陌生而复杂,认为 Lambda 会导致代码可读性下降,批评 Lambda 语法,甚至排斥它。
事实上,所有这些问题在尝试和熟悉之后可能都不是问题。
那些对 Lambda 持怀疑态度的人也许可以采取增量使用 Lambda 的策略。先尝试在一些简单、低风险的场景中使用 Lambda,然后逐步增加 Lambda 表达式的使用频率和范围。
迭代和过滤集合
使用Lambda表达式结合Stream API可以实现集合的遍历和过滤,代码更少,更加简洁,易于阅读。
List<String> letters= Arrays.asList("a", "b", "c");
for (String letter : letters) {
if (letter.endsWith("c")) {
System.out.println(letter);
}
}
用 Lambda 重写:
List<String> letters= Arrays.asList("a", "b", "c");
letters.stream()
.filter(letter -> letter.endsWith("c"))
.forEach(System.out::println);
对集合的元素进行排序
使用 Lambda 表达式可以让您以更紧凑的形式将排序逻辑传递给排序方法,使代码更加简洁。
List<String> names = Arrays.asList("Aaron", "Bobby", "Charlotte");
Collections.sort(names, new Comparator<String>() {
public int compare(String name1, String name2) {
return name1.compareTo(name2);
}
});
用 Lambda 重写:
List<String> names = Arrays.asList("Aaron", "Bobby", "Charlotte");
names.sort((name1, name2) -> name1.compareTo(name2));
集合上的聚合操作
Lambda表达式结合Stream API可以更优雅地实现对集合元素的聚合操作,例如求和、求平均等。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = 0;
for (Integer num : numbers) {
sum += num;
}
用 Lambda 重写:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.reduce(0, Integer::sum);
条件过滤和默认值设置
使用Lambda的Optional类可以更优雅地处理条件过滤和默认值设置的逻辑。
String name = "Aaron";
if (name != null && name.length() > 0) {
System.out.println("Hello, " + name);
} else {
System.out.println("Hello, Stranger");
}
用 Lambda 重写:
String name = "Aaron";
name = Optional.ofNullable(name)
.filter(n -> n.length() > 0)
.orElse("Stranger");
System.out.println("Hello, " + name);
简化匿名内部类
您可以简化代码并同时提高可读性。 举个创建线程的例子,传统的匿名内部类实现线程的语法比较冗长,而Lambda表达式可以用更简洁的方式达到同样的结果。
new Thread(new Runnable() {
public void run() {
System.out.println("Thread is running.");
}
}).start();
用 Lambda 重写:
new Thread(() -> System.out.println("Thread is running.")).start();
new Thread(() -> {
// do something
}).start();
集合元素的变换
使用Lambda的map方法可以更优雅地变换集合元素,提高代码可读性。
List<String> names = Arrays.asList("Aaron", "Bobby", "Charlotte");
List<String> uppercaseNames = new ArrayList<>();
for (String name : names) {
uppercaseNames.add(name.toUpperCase());
}
用 Lambda 重写:
List<String> names = Arrays.asList("Aaron", "Bobby", "Charlotte");
List<String> uppercaseNames = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
集合的分组和计数
以更紧凑的形式传递分组和计数的逻辑,避免了匿名内部类的繁琐声明和实现。 通过groupingBy、counting、summingInt等方法,代码更加流畅、直观、优雅。
Grouping:
List<String> names = Arrays.asList("Aaron", "Bobby", "Charlotte");
Map<Integer, List<String>> namesGroupByLength = new HashMap<>();
for (String name : names) {
int length = name.length();
if (!namesGroupByLength.containsKey(length)) {
namesGroupByLength.put(length, new ArrayList<>());
}
namesByLength.get(length).add(name);
}
System.out.println("Names grouped by length: " + namesGroupByLength);
用 Lambda 重写:
List<String> names = Arrays.asList("Aaron", "Bobby", "Charlotte");
Map<Integer, List<String>> namesGroupByLength = names.stream()
.collect(Collectors.groupingBy(String::length));
System.out.println("Names grouped by length: " + namesGroupByLength);
Counting:
List<String> names = Arrays.asList("Aaron", "Bobby", "Charlotte");
int namesStartWithA = 0;
for (String name : names) {
if (name.contains("A")) {
namesStartWithA++;
}
}
System.out.println("Number of names containing 'A': " + namesStartWithA);
用 Lambda 重写:
List<String> names = Arrays.asList("Aaron", "Bobby", "Charlotte");
long namesStartWithA = names.stream()
.filter(name -> name.contains("A"))
.count();
System.out.println("Number of names containing 'A': " + namesStartWithA);
大数据量集合的并行处理
当集合中的数据量较大时,很容易通过Lambda结合Stream API进行并行处理,以充分利用多核处理器,提高程序执行效率。 假设我们有一个包含一百万个整数的列表,并且我们想要计算这些整数的平均值:
List<Integer> numbers = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
numbers.add(ThreadLocalRandom.current().nextInt(100));
}
//
long startTimeSeq = System.currentTimeMillis();
double averageSequential = numbers.stream()
.mapToInt(Integer::intValue)
.average()
.getAsDouble();
long endTimeSeq = System.currentTimeMillis();
System.out.println("Sequential Average: " + averageSequential);
System.out.println("Time taken (Sequential): " + (endTimeSeq - startTimeSeq) + "ms");
//Parallel
long startTimePar = System.currentTimeMillis();
double averageParallel = numbers.parallelStream()
.mapToInt(Integer::intValue)
.average()
.getAsDouble();
long endTimePar = System.currentTimeMillis();
System.out.println("Parallel Average: " + averageParallel);
System.out.println("Time taken (Parallel): " + (endTimePar - startTimePar) + "ms");
//Sequential Average: 59.4451232
//Time taken (Sequential): 10ms
//Parallel Average: 59.4451232
//Time taken (Parallel): 3ms
可以看出,顺序流和并行流获得相同的平均值,但并行流的处理时间明显小于顺序流。 这是因为并行流能够将任务拆分为多个较小的任务,并在多个处理器核心上同时执行这些任务。
Lambda 的使用场景远不止这些,可以灵活运用在多线程、文件操作等场景,熟悉后可以让代码更加简洁,编程更加精确优雅。
在编写代码时,改变偏见需要我们尝试并采取行动。 有时,我们可能对某种编程语言、框架或设计模式有偏见,认为它们不适合或不好用。 然而,只有尝试去理解和实践它们,我们才能真正知道它们的优点和缺点。