深入理解Java中的Lambda表达式和Stream API

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()方法是转换的时候使用,例子如下:

  1. 类型转换:例如,将流中的每个整数转换为其字符串表示形式。
  2. 数据提取:从对象流中提取特定的数据。例如,从一系列的人员对象中提取每个人的名字。
  3. 数据转换:例如,有一个字符串列表,将每个字符串转换为大写。
  4. 应用计算:例如,将流中的每个数字平方。
⑤聚合

对集合进行某种形式的聚合操作,如求和、求平均、找最大值等。

计算数字列表的总和:

常规方法:

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编程变得更为高效和优雅。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值