跳转至

Java Stream mapToInt 深度解析

简介

在 Java 编程中,Stream API 是一个强大的工具,它为处理集合和数组提供了一种函数式、声明式的方式。mapToInt 是 Stream API 中的一个重要方法,它允许将流中的元素映射为 int 类型的值,然后可以进行各种聚合操作。本文将详细介绍 mapToInt 的基础概念、使用方法、常见实践以及最佳实践,帮助你更好地理解和运用这一特性。

目录

  1. 基础概念
  2. 使用方法
    • 从对象流映射到 int
    • 从数组创建流并映射到 int
  3. 常见实践
    • 计算总和
    • 获取最大值
    • 获取平均值
  4. 最佳实践
    • 避免装箱和拆箱
    • 结合其他 Stream 操作
  5. 小结
  6. 参考资料

基础概念

mapToIntjava.util.stream.Stream 接口中的一个方法,它用于将流中的每个元素映射为一个 int 类型的值。这个方法返回一个 IntStream,这是一个专门用于处理 int 类型数据的流。IntStream 提供了许多聚合操作,如 sum()max()average() 等,使得对 int 类型数据的处理更加方便和高效。

使用方法

从对象流映射到 int

假设我们有一个包含 Person 对象的列表,每个 Person 对象有一个 age 属性,我们想要获取所有人的年龄组成的 int 流。

import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

class Person {
    private int age;

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

    public int getAge() {
        return age;
    }
}

public class StreamMapToIntExample {
    public static void main(String[] args) {
        List<Person> people = new ArrayList<>();
        people.add(new Person(25));
        people.add(new Person(30));
        people.add(new Person(35));

        IntStream ageStream = people.stream()
             .mapToInt(Person::getAge);

        ageStream.forEach(System.out::println);
    }
}

在上述代码中,我们首先创建了一个 Person 类,然后创建了一个包含多个 Person 对象的列表。接着,我们使用 stream() 方法将列表转换为流,再通过 mapToInt 方法将每个 Person 对象映射为其 age 属性对应的 int 值,最终得到一个 IntStream。最后,我们使用 forEach 方法打印出流中的每个年龄值。

从数组创建流并映射到 int

如果我们有一个包含字符串数字的数组,想要将其转换为 int 流进行进一步处理。

import java.util.stream.IntStream;

public class ArrayMapToIntExample {
    public static void main(String[] args) {
        String[] numberStrings = {"1", "2", "3", "4", "5"};

        IntStream intStream = java.util.Arrays.stream(numberStrings)
             .mapToInt(Integer::parseInt);

        intStream.forEach(System.out::println);
    }
}

在这个例子中,我们首先有一个包含字符串数字的数组。通过 Arrays.stream 方法将数组转换为流,然后使用 mapToInt 方法将每个字符串映射为对应的 int 值,生成一个 IntStream,并打印出流中的每个 int 值。

常见实践

计算总和

使用 mapToInt 结合 sum 方法可以很方便地计算流中元素的总和。

import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

class Product {
    private int price;

    public Product(int price) {
        this.price = price;
    }

    public int getPrice() {
        return price;
    }
}

public class SumExample {
    public static void main(String[] args) {
        List<Product> products = new ArrayList<>();
        products.add(new Product(10));
        products.add(new Product(20));
        products.add(new Product(30));

        int totalPrice = products.stream()
             .mapToInt(Product::getPrice)
             .sum();

        System.out.println("Total price: " + totalPrice);
    }
}

在这个例子中,我们有一个 Product 类,每个 Product 对象有一个 price 属性。通过 mapToInt 将每个产品的价格映射为 int 流,然后使用 sum 方法计算出所有产品价格的总和。

获取最大值

使用 mapToInt 结合 max 方法可以获取流中元素的最大值。

import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

class Student {
    private int score;

    public Student(int score) {
        this.score = score;
    }

    public int getScore() {
        return score;
    }
}

public class MaxExample {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        students.add(new Student(85));
        students.add(new Student(90));
        students.add(new Student(95));

        int maxScore = students.stream()
             .mapToInt(Student::getScore)
             .max()
             .orElse(0);

        System.out.println("Max score: " + maxScore);
    }
}

这里我们有一个 Student 类,每个 Student 对象有一个 score 属性。通过 mapToInt 将学生的分数映射为 int 流,然后使用 max 方法获取最高分。由于 max 方法返回一个 OptionalInt,我们使用 orElse 方法在流为空时返回一个默认值 0

获取平均值

使用 mapToInt 结合 average 方法可以获取流中元素的平均值。

import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

class Employee {
    private int salary;

    public Employee(int salary) {
        this.salary = salary;
    }

    public int getSalary() {
        return salary;
    }
}

public class AverageExample {
    public static void main(String[] args) {
        List<Employee> employees = new ArrayList<>();
        employees.add(new Employee(5000));
        employees.add(new Employee(6000));
        employees.add(new Employee(7000));

        double averageSalary = employees.stream()
             .mapToInt(Employee::getSalary)
             .average()
             .orElse(0);

        System.out.println("Average salary: " + averageSalary);
    }
}

在这个例子中,我们有一个 Employee 类,每个 Employee 对象有一个 salary 属性。通过 mapToInt 将员工的工资映射为 int 流,然后使用 average 方法获取平均工资。同样,由于 average 方法返回一个 OptionalDouble,我们使用 orElse 方法在流为空时返回一个默认值 0

最佳实践

避免装箱和拆箱

mapToInt 方法的一个重要优势是避免了不必要的装箱和拆箱操作。如果使用普通的 Stream<Integer>,在进行数值计算时会频繁地进行装箱(将 int 转换为 Integer)和拆箱(将 Integer 转换为 int),这会带来一定的性能开销。使用 mapToInt 直接生成 IntStream,可以避免这种性能损耗,提高程序的执行效率。

结合其他 Stream 操作

mapToInt 可以与其他 Stream 操作,如 filtersorted 等结合使用,以实现更复杂的数据处理逻辑。例如,我们可以先过滤出满足条件的元素,再将其映射为 int 流进行聚合操作。

import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

class Fruit {
    private String name;
    private int price;

    public Fruit(String name, int price) {
        this.name = name;
        this.price = price;
    }

    public int getPrice() {
        return price;
    }
}

public class ComplexOperationExample {
    public static void main(String[] args) {
        List<Fruit> fruits = new ArrayList<>();
        fruits.add(new Fruit("Apple", 10));
        fruits.add(new Fruit("Banana", 5));
        fruits.add(new Fruit("Orange", 8));

        int totalPriceOfExpensiveFruits = fruits.stream()
             .filter(fruit -> fruit.getPrice() > 7)
             .mapToInt(Fruit::getPrice)
             .sum();

        System.out.println("Total price of expensive fruits: " + totalPriceOfExpensiveFruits);
    }
}

在这个例子中,我们首先过滤出价格大于 7 的水果,然后将这些水果的价格映射为 int 流,最后计算出这些水果的总价格。

小结

mapToInt 是 Java Stream API 中一个非常实用的方法,它能够将流中的元素方便地映射为 int 类型的值,进而进行各种聚合操作。通过避免装箱和拆箱以及结合其他 Stream 操作,我们可以更加高效地处理数据。希望通过本文的介绍,你对 mapToInt 的使用有了更深入的理解,并能在实际项目中灵活运用。

参考资料