☕️从小工到专家的 Java 进阶之旅:map()和flatMap()的区别

☕️从小工到专家的 Java 进阶之旅:map()和flatMap()的区别

你好,我是看山。

本文收录在 《从小工到专家的 Java 进阶之旅》 系列专栏。日拱一卒,功不唐捐。

一、Stream API 简介

Stream API 为处理集合数据提供了一种高效且简洁的方式。它允许我们以一种声明式的风格来操作数据,避免了传统的迭代器和循环方式带来的繁琐和易错性。

Stream API 可以对集合进行过滤、映射、归约等多种操作,而其中的 mapflatMap 操作在数据转换和处理复杂数据结构方面发挥着重要作用。

二、map 操作

基本概念

map 操作是 Stream API 中最常用的操作之一。它接收一个 Function 作为参数,这个函数会被应用到流中的每一个元素上,从而将流中的元素转换为新的元素。

例如,我们有一个包含整数的流,想要将每个整数都乘以 2:

public class MapExample {

    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        List<Integer> result = numbers.stream()
               .map(n -> n * 2)
               .collect(Collectors.toList());

        System.out.println(result);
    }
}

在上述代码中,map(n -> n * 2) 将流中的每个整数元素 n 转换为 n * 2

特点

  1. 元素一对一转换map 操作保持了流中元素的数量不变,只是对每个元素进行了单独的转换。
  2. 简单的数据转换:适用于简单的数据类型转换,比如将字符串转换为大写、将数字进行简单的数学运算等。

应用场景

  1. 数据类型转换:从一种数据类型转换为另一种数据类型。例如,将一个包含 Double 类型元素的流转换为包含 Integer 类型元素的流。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class MapDataTypeConversion {

    public static void main(String[] args) {
        List<Double> doubles = Arrays.asList(1.1, 2.2, 3.3);

        List<Integer> integers = doubles.stream()
               .map(d -> d.intValue())
               .collect(Collectors.toList());

        System.out.println(integers);
    }
}

  1. 对象属性提取:当我们有一个对象流时,可以使用 map 操作提取对象的某个属性值,形成一个新的流。
import java.util.ArrayList;
import java.util.List;

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

public class MapObjectPropertyExtraction {

    public static void main(String[] args) {
        List<Person> people = new ArrayList<>();
        people.add(new Person("Alice", 25));
        people.add(new Person("Bob", 30));

        List<String> names = people.stream()
               .map(Person::getName)
               .collect(Collectors.toList());

        System.out.println(names);
    }
}

三、flatMap 操作

基本概念

flatMap 操作比 map 操作更为复杂。它接收一个函数作为参数,这个函数将流中的每个元素转换为一个流,然后将这些流合并(扁平化)为一个单一的流。

例如,我们有一个包含多个字符串的流,每个字符串都包含一些用逗号分隔的单词,我们想要将所有的单词提取到一个流中:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class FlatMapExample {

    public static void main(String[] args) {
        List<String> strings = Arrays.asList("apple,banana", "cherry,date");

        List<String> words = strings.stream()
               .flatMap(s -> Arrays.stream(s.split(",")))
               .collect(Collectors.toList());

        System.out.println(words);
    }
}

在上述代码中,flatMap(s -> Arrays.stream(s.split(",")) 将每个字符串 s 转换为一个包含其分割后的单词的流,然后将这些流合并为一个单一的流。

特点

  1. 处理嵌套流flatMap 主要用于处理嵌套的流结构,将嵌套的流扁平化。
  2. 元素数量可能改变:与 map 不同,flatMap 操作后的流中的元素数量可能会发生变化,取决于内部流的元素数量。

应用场景

  1. 处理二维数组或多维数组:将二维数组或多维数组转换为一维数组。
import java.util.Arrays;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class FlatMap2DArray {

    public static void main(String[] args) {
        int[][] matrix = {
                {1, 2, 3},
                {4, 5, 6},
                {7, 8, 9}
        };

        // 将二维数组转换为一维数组
        int[] flatArray = Arrays.stream(matrix)
               .flatMapToInt(IntStream::of)
               .toArray();

        System.out.println(Arrays.toString(flatArray));
    }
}

  1. 处理复杂的数据结构:当数据结构中包含嵌套的集合时,使用 flatMap 可以方便地将所有元素提取到一个流中进行处理。
import java.util.ArrayList;
import java.util.List;

class Department {
    private String name;
    private List<Employee> employees;

    public Department(String name, List<Employee> employees) {
        this.name = name;
        this.employees = employees;
    }

    public List<Employee> getEmployees() {
        return employees;
    }
}

class Employee {
    private String name;

    public Employee(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

public class FlatMapComplexDataStructure {

    public static void main(String[] args) {
        List<Department> departments = new ArrayList<>();

        List<Employee> employees1 = new ArrayList<>();
        employees1.add(new Employee("Alice"));
        employees1.add(new Employee("Bob"));

        List<Employee> employees2 = new ArrayList<>();
        employees2.add(new Employee("Charlie"));
        employees2.add(new Employee("David"));

        departments.add(new Department("HR", employees1));
        departments.add(new Department("IT", employees2));

        // 提取所有员工的名字到一个流中
        List<String> allEmployeeNames = departments.stream()
               .flatMap(d -> d.getEmployees().stream())
               .map(Employee::getName)
               .collect(Collectors.toList());

        System.out.println(allEmployeeNames);
    }
}

四、map 和 flatMap 的对比

操作对象

  • map:操作的是单个元素,将单个元素转换为另一个元素。
  • flatMap:操作的是流中的每个元素,这些元素本身也是流(或者可以转换为流),然后将这些内部流合并为一个单一的流。

返回结果

  • map:返回的流中的元素是对原始流中元素进行转换后的结果,元素数量不变。
  • flatMap:返回的是一个将内部流扁平化后的流,元素数量可能会改变。

文末总结

在 Stream API 中,mapflatMap 都是非常重要的数据转换操作。

map 适用于简单的一对一元素转换场景,而 flatMap 则在处理嵌套流和复杂数据结构时具有独特的优势。

通过合理地选择和使用这两个操作,可以更高效地处理集合数据,实现简洁、高效和可读的代码。

在实际编程中,根据数据的结构和处理需求,灵活运用 mapflatMap 能够使我们更好地利用 Stream API 进行数据处理。

青山不改,绿水长流,我们下次见。

推荐阅读

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

看山

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值