Java值得使用Lambda的8个场景合集

 更新时间:2023年08月04日 14:25:40   作者:一只叫煤球的猫  
可能对不少人来说,Lambda显得陌生又复杂,觉得Lambda会导致代码可读性下降,但毕竟2023年了,JDK都出了那么多新版本,是时候试试Lambda了

前言

可能对不少人来说,Lambda显得陌生又复杂,觉得Lambda会导致代码可读性下降,诟病Lambda语法,甚至排斥。

其实所有的这些问题,在尝试并熟悉后,可能都不是问题。

对Lambda持怀疑态度的人,也许可以采取渐进式使用Lambda的策略。在一些简单和低风险的场景下先尝试使用Lambda,逐渐增加Lambda表达式的使用频率和范围。

毕竟2023年了,JDK都出了那么多新版本,是时候试试Lambda了!

耐心看完,你一定有所收获。

1. 对集合进行遍历和筛选

使用Lambda表达式结合Stream API可以在更少的代码量下实现集合的遍历和筛选,更加简洁和易读。

原来的写法:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
for (Integer num : numbers) {
    if (num % 2 == 0) {
        System.out.println(num);
    }
}

优化的Lambda写法:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream()
       .filter(num -> num % 2 == 0)
       .forEach(System.out::println);

2. 对集合元素进行排序

使用Lambda表达式可以将排序逻辑以更紧凑的形式传递给sort方法,使代码更加简洁。

原来的写法:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
Collections.sort(names, new Comparator<String>() {
    public int compare(String name1, String name2) {
        return name1.compareTo(name2);
    }
});

优化的Lambda写法:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
names.sort((name1, name2) -> name1.compareTo(name2));

3. 集合的聚合操作

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);

4. 条件过滤和默认值设置

使用Lambda的Optional类可以更加优雅地处理条件过滤和默认值设置的逻辑。

原来的写法:

String name = "Alice";
if (name != null && name.length() > 0) {
    System.out.println("Hello, " + name);
} else {
    System.out.println("Hello, Stranger");
}

Lambda写法:

String name = "Alice";
name = Optional.ofNullable(name)
               .filter(n -> n.length() > 0)
               .orElse("Stranger");
System.out.println("Hello, " + name);

5. 简化匿名内部类

可以简化代码,同时提高代码可读性。

举个创建Thread的例子,传统方式使用匿名内部类来实现线程,语法较为冗长,而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(() -> {
    // 做点什么
}).start();

这种写法也常用于简化回调函数,再举个例子:

假设我们有一个简单的接口叫做Calculator,它定义了一个单一的方法calculate(int a, int b)来执行数学运算:

// @FunctionalInterface: 标识接口是函数式接口,只包含一个抽象方法,从而能够使用Lambda表达式来实现接口的实例化
@FunctionalInterface 
interface Calculator {
    int calculate(int a, int b);
}

现在,让我们创建一个名为CallbackExample的类。该类有一个名为operate的方法,它接受两个整数和一个Calculator接口作为参数。该方法将使用提供的Calculator接口执行计算并返回结果:

public class CallbackExample {
    public static int operate(int a, int b, Calculator calculator) {
        return calculator.calculate(a, b);
    }
    public static void main(String[] args) {
        int num1 = 10;
        int num2 = 5;
        // 使用Lambda作为回调
        int sum = operate(num1, num2, (x, y) -> x + y);
        int difference = operate(num1, num2, (x, y) -> x - y);
        int product = operate(num1, num2, (x, y) -> x * y);
        int division = operate(num1, num2, (x, y) -> x / y);
        System.out.println("Sum: " + sum);
        System.out.println("Difference: " + difference);
        System.out.println("Product: " + product);
        System.out.println("Division: " + division);
    }
}

通过在方法调用中直接定义计算的行为,我们不再需要为每个运算创建多个实现Calculator接口的类,使得代码更加简洁和易读

6. 集合元素的转换

使用Lambda的map方法可以更优雅地对集合元素进行转换,提高代码的可读性

原来的写法:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> uppercaseNames = new ArrayList<>();
for (String name : names) {
    uppercaseNames.add(name.toUpperCase());
}

Lambda写法:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> uppercaseNames = names.stream()
                                   .map(String::toUpperCase)
                                   .collect(Collectors.toList());

7. 对集合进行分组和统计

以更紧凑的形式传递分组和统计的逻辑,避免了繁琐的匿名内部类的声明和实现。

通过groupingBy、counting、summingInt等方法,使得代码更加流畅、直观且优雅。

传统写法:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Amy", "Diana");
// 对名字长度进行分组
Map<Integer, List<String>> namesByLength = new HashMap<>();
for (String name : names) {
    int length = name.length();
    if (!namesByLength.containsKey(length)) {
        namesByLength.put(length, new ArrayList<>());
    }
    namesByLength.get(length).add(name);
}
System.out.println("Names grouped by length: " + namesByLength);
// 统计名字中包含字母'A'的个数
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Amy", "Diana");
int namesWithA = 0;
for (String name : names) {
    if (name.contains("A")) {
        namesWithA++;
    }
}
System.out.println("Number of names containing 'A': " + namesWithA);

Lambda写法:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Amy", "Diana");
// 使用Lambda表达式对名字长度进行分组
Map<Integer, List<String>> namesByLength = names.stream()
        .collect(Collectors.groupingBy(String::length));
System.out.println("Names grouped by length: " + namesByLength);
// 使用Lambda表达式统计名字中包含字母'A'的个数
long namesWithA = names.stream()
        .filter(name -> name.contains("A"))
        .count();
System.out.println("Number of names containing 'A': " + namesWithA);

8. 对大数据量集合的并行处理

当集合的数据量很大时,通过Lambda结合Stream API可以方便地进行并行处理,充分利用多核处理器的优势,提高程序的执行效率。

假设我们有一个包含一百万个整数的列表,我们想要计算这些整数的平均值:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class ParallelStreamExample {
    public static void main(String[] args) {
        // 创建一个包含一百万个随机整数的列表
        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");
        // 并行流的处理
        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");
    }
}

分别使用顺序流和并行流来计算列表中整数的平均值:

  • 顺序流:通过stream()方法获取流,使用mapToInt将Integer转换为int,然后使用average()方法计算平均值
  • 并行流:使用parallelStream()方法获取并行流,其他步骤与顺序流相同

查看输出结果:

Sequential Average: 49.517461
Time taken (Sequential): 10ms
Parallel Average: 49.517461
Time taken (Parallel): 3ms

可以看出,顺序流和并行流得到了相同的平均值,但并行流的处理时间明显少于顺序流。因为并行流能够将任务拆分成多个小任务,并在多个处理器核心上同时执行这些任务。

当然并行流也有缺点:

  • 对于较小的数据集,可能并行流更慢
  • 数据处理本身的开销较大,比如复杂计算、大量IO操作、网络通信等,可能并行流更慢
  • 可能引发线程安全问题

收尾

Lambda的使用场景远不止这些,在多线程、文件操作等场景中也都能灵活运用,一旦熟悉后可以让代码更简洁,实现精准而优雅的编程。

写代码时,改变偏见需要我们勇于尝试和付诸行动。有时候,我们可能会对某种编程语言、框架或设计模式持有偏见,认为它们不适合或不好用。但是,只有尝试去了解和实践,我们才能真正知道它们的优点和缺点。

当我们愿意打破旧有的观念,敢于尝试新的技术和方法时,我们就有机会发现新的可能性和解决问题的新途径。不要害怕失败或犯错,因为每一次尝试都是我们成长和进步的机会。

只要我们保持开放的心态,不断学习和尝试,我们就能够超越偏见,创造出更优秀的代码和解决方案。

所以,让我们在编程的路上,积极地去挑战和改变偏见。用行动去证明,只有不断地尝试,我们才能取得更大的进步和成功。让我们敢于迈出第一步,勇往直前,一同创造出更美好的编程世界!

以上就是Java值得使用Lambda的8个场景合集的详细内容,更多关于Java Lambda的资料请关注脚本之家其它相关文章!

相关文章

  • 使用java web 在jsp文件及Class中连接MySQL和SQLserver 的驱动方法

    使用java web 在jsp文件及Class中连接MySQL和SQLserver 的驱动方法

    这篇文章主要介绍了使用java web 在jsp文件及Class中连接MySQL和SQLserver的驱动方法的相关资料,本文介绍的非常详细,具有参考借鉴价值,需要的朋友可以参考下
    2016-10-10
  • Spring Boot Shiro auto-configure工作流程详解

    Spring Boot Shiro auto-configure工作流程详解

    这篇文章主要为大家介绍了Spring Boot Shiro auto-configure工作流程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • Java中List集合的常用方法详解

    Java中List集合的常用方法详解

    这篇文章主要为大家详细介绍了Java中List集合的常用方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • IDEA 中创建并部署 JavaWeb 程序的方法步骤(图文)

    IDEA 中创建并部署 JavaWeb 程序的方法步骤(图文)

    本文主要介绍了IDEA 中创建并部署 JavaWeb 程序的方法步骤,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • Springboot之修改启动端口的两种方式(小结)

    Springboot之修改启动端口的两种方式(小结)

    这篇文章主要介绍了Springboot之修改启动端口的两种方式(小结),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • Java详解实现多线程的四种方式总结

    Java详解实现多线程的四种方式总结

    哈哈!经过一个阶段的学习,Java基础知识学习终于到多线程了!Java多线程以及后面互斥锁的概念都是Java基础学习的难点,所以我做了一个总结,希望对大家也有帮助
    2022-07-07
  • Java中replace与replaceAll的区别与测试

    Java中replace与replaceAll的区别与测试

    replace和replaceAll是JAVA中常用的替换字符的方法,下面这篇文章主要给大家介绍了关于Java中replace与replaceAll的区别与测试,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-09-09
  • Java线程死锁代码详解

    Java线程死锁代码详解

    本篇文章主要介绍了Java线程死锁代码详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2021-11-11
  • Java多线程atomic包介绍及使用方法

    Java多线程atomic包介绍及使用方法

    这篇文章主要介绍了Java多线程atomic包介绍及使用方法,涉及原子更新基本类型介绍及代码示例,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • Java数据结构之KMP算法详解以及代码实现

    Java数据结构之KMP算法详解以及代码实现

    KMP算法是一种改进的字符串匹配算法,核心是利用之前的匹配失败时留下的信息,选择最长匹配长度直接滑动,从而减少匹配次数。本文主要介绍了KMP算法的原理与实现,需要的可以参考一下
    2022-12-12

最新评论