1.什么是lambda表达式?
Lambda表达式是一个简化版本的匿名函数。主要目的是提供一种简洁、清晰的方式来表示函数式接口。
2.什么是函数式接口?
函数式接口是只有一个抽象方法的接口,可以被@FunctionalInterface
注解标记。
@FunctionalInterface
public interface MyFunctionalInterface {
void execute();
}
3.示例解释
假如我们有个一简单的接口:
interface Greeting {
void sayHello(String name);
}
用传统的匿名内部类,我们可以这样实现:
Greeting greeting = new Greeting() {
@Override
public void sayHello(String name) {
System.out.println("Hello, " + name);
}
};
但是,使用lambda表达式,我们可以简化为:
Greeting greeting2 = (name) -> System.out.println("Hello, " + name);
所以,一个lambda表达式由3个部分组成:
注意:①在lambda表达式中,参数的类型通常是可以从上下文中推断出来的,因此,参数不需要写类型。
②当lambda表达式的主体只有一个语句时,你可以省略花括号:{}。
4.常用的lambda表达式的场景
初步了解了lambda表达式之后,我们应该怎么应用到那些场景,怎么写代码呢?以下是一些常用的场景。
①遍历:对集合进行遍历
用for循环遍历
List<String> names= Arrays.asList("apple","banana","orange");
for (String name : list) {
System.out.println(name);
}
分析:
参数:name
小箭头:->
代码块:System.out.println(name);
所以用lambda表达式进行遍历代码如下:
names.forEach(name -> System.out.println(name));
对于上面的lambda表达式:
name -> System.out.println(name)
lambda表达式接收一个参数name,没有进行任何操作,然后直接将其传递给System.out.println方法。就可以使用方法引用。方法引用的语法是:
对象::方法名
类::静态方法名
类::实例方法名
所以根据对象::方法名的语法,可以简化为:
names.forEach(System.out::println);
②排序:对集合元素进行排序
按字符串长度进行排序:
使用传统的匿名内部类来排序:
List<String> names = Arrays.asList("Charlie", "Bob", "Alice");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return Integer.compare(s1.length(), s2.length());
}
});
分析:
参数:s1,s2
小箭头:->
代码块:return Integer.compare(s1.length(), s2.length());
注意:当lambda表达式只有一个语句,并且这个语句产生一个值,这个值将自动成为lambda表达式的返回值,因此不需要显式地使用return
关键字。
所以我们使用lambda进行排序代码如下:
names.sort((s1, s2) -> Integer.compare(s1.length(), s2.length()));
③筛选:对集合进行筛选
筛选出长度大于3的字符串:
常规写法:
List<String> names = Arrays.asList("Al", "Alice", "Bob");
List<String> result = new ArrayList<>();
for (String name : names) {
if (name.length() > 3) {
result.add(name);
}
}
// 打印结果
for (String name : result) {
System.out.println(name);
}
分析:
参数:name
小箭头:->
代码块:name.length() > 3
当我们想对集合(如列表、集合、映射等)进行一系列的变换、筛选、排序或其他操作时,通常会使用流(Streams)API,在流上的筛选操作,是filter()
方法,在括号内添加筛选条件,也就是我们上面的代码块。 所以使用lambda表达式代码如下:
List<String> names = Arrays.asList("Al", "Alice", "Bob");
List<String> filteredNames = names.stream()
.filter(name -> name.length() > 3)
.collect(Collectors.toList());
filteredNames.forEach(name -> System.out.println(name)); // 输出: Alice
使用filter()
方法方法后,会将筛选出来的数据返回一个新的流,这时候我们用collect()方法,它会消耗流并产生一个结果,最后我们使用Collectors.toList()
来指示我们想要将结果收集到一个新的列表中,即这一步操作,就是把流返回成一个List集合。
④映射
将所有字符串转化成大写:
常规写法:
List<String> names = Arrays.asList("alice", "bob", "charlie");
List<String> upperCaseNames = new ArrayList<>();
// 遍历
for (String name : names) {
upperCaseNames.add(name.toUpperCase());
}
// 打印
for (String name : upperCaseNames) {
System.out.println(name);
}
分析:
参数:name
小箭头:->
代码块:name.toUpperCase()
当我们想对流中的每个元素进行某种形式的转换或操作时,使用map()方法就可以了。所以使用lambda表达式代码如下:
List<String> names = Arrays.asList("alice", "bob", "charlie");
List<String> upperCaseNames = names.stream()
.map(name -> name.toUpperCase())
.collect(Collectors.toList());
upperCaseNames.forEach(name -> System.out.println(name)); // 输出: ALICE, BOB, CHARLIE
map()方法是转换的时候使用,例子如下:
- 类型转换:例如,将流中的每个整数转换为其字符串表示形式。
- 数据提取:从对象流中提取特定的数据。例如,从一系列的人员对象中提取每个人的名字。
- 数据转换:例如,有一个字符串列表,将每个字符串转换为大写。
- 应用计算:例如,将流中的每个数字平方。
⑤聚合
对集合进行某种形式的聚合操作,如求和、求平均、找最大值等。
计算数字列表的总和:
常规方法:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = 0;
for (Integer number : numbers) {
sum += number;
}
System.out.println(sum); // 输出: 15
使用lambda表达式代码如下:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream().mapToInt(i -> i).sum();
System.out.println(sum); // 输出: 15
mapToInt
:接受一个函数作为参数,并返回一个 IntStream
(一个特殊的流,用于处理基本的 int
类型的元素)。
sum():这是IntStream的一个终端操作,它返回流中的所有元素的总和。
⑥并行处理
使用 parallelStream
以并行的方式处理集合。
并行计算所有数字的平方和:
常规方法:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sumOfSquares = 0;
for (Integer number : numbers) {
sumOfSquares += number * number;
}
System.out.println(sumOfSquares); // 输出: 55
使用lambda表达式代码如下:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sumOfSquares = numbers.parallelStream()
.mapToInt(i -> i * i)
.sum();
System.out.println(sumOfSquares); // 输出: 55
5.总结
在现代Java编程中,lambda表达式和Stream API为我们提供了一种更加简洁、声明式的方式来处理集合和数据流。很多时候,为了利用这些特性,我们会把集合转换为流,执行一系列操作,最后再将其收集回集合或其他数据结构。转换成流之后,我们可以利用各种方法来进行筛选、映射、排序、归约等操作。这种风格的编程让代码更为直观,有助于提高代码的可读性和维护性。大家还是需要通过不断的实践和练习,才可以更熟练地应用,使Java编程变得更为高效和优雅。