授课语音

Java8的Lambda和流式编程

1. 介绍

Java8引入了Lambda表达式和Stream API的强大特性,旨在简化代码,提高可读性和可维护性,极大地提高了开发效率。

Lambda表达式

Lambda表达式是一种函数式编程的方式,它允许函数作为参数传递。实际开发中,Lambda表达式被广泛应用于集合操作和并发编程。其主要特性包括:

  • 语法简洁:

    • 单个表达式:(params) -> expression
    • 多个语句:{ (params) -> {statements}}
  • 函数式接口:只包含一个抽象方法的接口,例如RunnableCallable等。

  • 方法引用:使用::符号引用方法,例如String::length

Stream API

Stream API提供了一种声明式的方式来处理集合,包括过滤、映射、聚合等操作。流分为顺序流(顺序处理)和并行流(并行处理,充分利用多核处理器)。其主要特性包括:

  • 创建流:可以通过多种方式创建流,例如:

    • collection.stream()从集合中创建
    • Arrays.stream(array)从数组创建
    • Stream.generate()使用生成器创建
    • Stream.iterate()使用迭代器创建
  • 中间操作:返回一个新的流,可以链式使用,例如:

    • filter()过滤
    • map()映射
    • sorted()排序
  • 终止操作:返回一个非流结果,并触发流处理,例如:

    • forEach()遍历
    • collect()
    • reduce()
  • 聚合操作:方便对数据进行统计和分析,例如:

    • countsumaveragemaxmin
  • 收集操作:将流的元素收集到集合中,例如:

    • toListtoSettoMap

2. 代码案例

package com.zhilitech.lambda;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

// 定义Person类
class Person {
    private String name; // 姓名
    private int age; // 年龄
    private String occupation; // 职业

    // 构造函数
    public Person(String name, int age, String occupation) {
        this.name = name;
        this.age = age;
        this.occupation = occupation;
    }

    // Getter方法
    public String getName() {
        return name; // 返回姓名
    }

    public int getAge() {
        return age; // 返回年龄
    }

    public String getOccupation() {
        return occupation; // 返回职业
    }

    @Override
    public String toString() {
        // 返回Person对象的字符串表示
        return "Person{name='" + name + "', age=" + age + ", occupation='" + occupation + "'}";
    }
}

public class LambdaStreamEnhancedExample {
    public static void main(String[] args) {
        // 创建一个Person类的列表
        List<Person> people = Arrays.asList(
                new Person("Alice", 30, "Engineer"),
                new Person("Bob", 25, "Designer"),
                new Person("Charlie", 35, "Manager"),
                new Person("David", 40, "Engineer"),
                new Person("Eve", 28, "Designer")
        );

        // 使用自定义函数式接口将姓名转换为大写
        Function<Person, String> nameToUpperCase = person -> person.getName().toUpperCase();
        List<String> upperCaseNames = people.stream()
                .map(nameToUpperCase) // 使用map操作将每个姓名转换为大写
                .toList();
        System.out.println("使用自定义函数式接口转换的姓名为大写: " + upperCaseNames);
        // 输出: [ALICE, BOB, CHARLIE, DAVID, EVE]

        // 使用方法引用获取姓名
        List<String> namesViaMethodReference = people.stream()
                .map(Person::getName) // 通过方法引用获取姓名
                .toList();
        System.out.println("使用方法引用获取的姓名: " + namesViaMethodReference);
        // 输出: [Alice, Bob, Charlie, David, Eve]

        // 使用Stream API计算所有人员的平均年龄
        OptionalDouble averageAgeOptional = people.stream()
                .mapToInt(Person::getAge) // 映射年龄
                .average(); // 计算平均值

        if (averageAgeOptional.isPresent()) {
            double averageAge = averageAgeOptional.getAsDouble(); // 获取平均年龄
            System.out.println("所有人员的平均年龄: " + averageAge);
            // 输出: 31.6
        } else {
            System.out.println("没有可用的平均年龄。");
        }

        double averageAge = averageAgeOptional.orElse(0);
        System.out.println("所有人员的平均年龄: " + averageAge);
        // 输出: 31.6

        // 使用Stream API根据职业进行分组
        Map<String, List<Person>> peopleByOccupation = people.stream()
                .collect(Collectors.groupingBy(Person::getOccupation)); // 按职业分组
        System.out.println("按职业分组的人: " + peopleByOccupation);
        // 输出: {Engineer=[...], Designer=[...], Manager=[...]}

        // 使用Stream API对人员按年龄排序
        List<Person> sortedByAge = people.stream()
                .sorted(Comparator.comparingInt(Person::getAge)) // 按年龄排序
                .toList();
        System.out.println("按年龄排序的人: " + sortedByAge);
        // 输出: [Person{name='Bob', age=25, ...}, ...]

        // 使用reduce计算总年龄
        int totalAge = people.stream()
                .map(Person::getAge) // 映射年龄
                .reduce(0, Integer::sum); // 计算总和
        System.out.println("所有人员的总年龄: " + totalAge);
        // 输出: 158

        // 使用toMap生成一个以姓名为键、年龄为值的Map
        Map<String, Integer> nameToAgeMap = people.stream()
                .collect(Collectors.toMap(Person::getName, Person::getAge)); // 生成姓名与年龄的映射
        System.out.println("姓名与年龄的映射: " + nameToAgeMap);
        // 输出: {Alice=30, Bob=25, ...}

        // 使用toSet生成一个包含所有职业的Set
        Set<String> occupationsSet = people.stream()
                .map(Person::getOccupation) // 映射职业
                .collect(Collectors.toSet()); // 收集到Set中
        System.out.println("所有职业的集合: " + occupationsSet);
        // 输出: [Designer, Manager, Engineer]

        // 使用并行流进行并行处理
        List<Person> sortedByAgeParallel = people.parallelStream()
                .sorted(Comparator.comparingInt(Person::getAge)) // 使用并行流按年龄排序
                .toList();
        System.out.println("使用并行流按年龄排序的人: " + sortedByAgeParallel);
        // 输出: [Person{name='Bob', age=25, ...}, ...]
    }
}

在这个代码示例中,我们定义了一个Person类,包含姓名、年龄和职业。我们创建了一个List,然后使用Lambda表达式和Stream API对人员数据进行各种操作,包括转换姓名、计算平均年龄、按职业分组、排序、计算总年龄等。通过使用方法引用和函数式接口,我们能够更简洁地处理数据,提高了代码的可读性和可维护性。

去1:1私密咨询

系列课程: