Bootstrap

用 Lambda 表达式处理 Java Stream 流操作

在 Java 编程领域,Lambda 表达式与 Stream API 的组合堪称一对强大的搭档,极大地简化了集合数据处理的过程。本文将深入探讨如何借助 Lambda 表达式实现各种常见的 Stream 流操作。

List 转 Set

将 List 转换为 Set 是去除重复元素的便捷方式。利用 Stream 流,代码如下:

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class ListToSetExample {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(2);
        list.add(3);

        Set<Integer> set = list.stream()
              .collect(Collectors.toSet());

        System.out.println(set);
    }
}

通过stream()方法创建流,再使用collect(Collectors.toSet())将流中的元素收集到 Set 中,Set 的特性会自动剔除重复元素。

 

List 转 Map

当我们有一个对象 List,想以对象的某个属性为键构建 Map 时,可这样操作:

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

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 ListToMapExample {
    public static void main(String[] args) {
        List<Person> personList = new ArrayList<>();
        personList.add(new Person("Alice", 25));
        personList.add(new Person("Bob", 30));

        Map<String, Person> personMap = personList.stream()
              .collect(Collectors.toMap(Person::getName, p -> p));

        System.out.println(personMap);
    }
}

Collectors.toMap()的第一个参数指定键的提取方式,这里是Person::getName,第二个参数p -> p表示值就是对象本身。

Map 转 List

把 Map 的键值对转换为 List,能方便后续对键值对进行统一处理:

 

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class MapToListExample {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("key1", 1);
        map.put("key2", 2);

        List<Map.Entry<String, Integer>> entryList = map.entrySet()
              .stream()
              .collect(Collectors.toList());

        System.out.println(entryList);
    }
}

先通过entrySet()获取键值对集合,再用 Stream 流和collect(Collectors.toList())将其收集为 List。

过滤、求和与分组

(一)过滤:筛选符合条件元素

从 List 中筛选出偶数 此时我们会借助.filter方法:

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

public class FilterExample {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);

        List<Integer> evenList = list.stream()
              .filter(num -> num % 2 == 0)
              .collect(Collectors.toList());

        System.out.println(evenList);
    }
}

(二)求和:计算数值总和

对 List 中的整数求和:

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

public class SumExample {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);

        int sum = list.stream()
              .mapToInt(Integer::intValue)
              .sum();

        System.out.println(sum);
    }
}

mapToInt()将 Integer 流转换为 IntStream,再用sum()方法计算总和。

分组:按特定属性归类

对 Person 对象按年龄分组:

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

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 GroupingExample {
    public static void main(String[] args) {
        List<Person> personList = new ArrayList<>();
        personList.add(new Person("Alice", 25));
        personList.add(new Person("Bob", 25));
        personList.add(new Person("Charlie", 30));

        Map<Integer, List<Person>> groupedMap = personList.stream()
              .collect(Collectors.groupingBy(Person::getAge));

        System.out.println(groupedMap);
    }
}

map 与 reduce:元素转换与累积

(一)map:元素映射转换

将字符串 List 中的元素转为大写:

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

public class MapExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("hello");
        list.add("world");

        List<String> upperList = list.stream()
              .map(String::toUpperCase)
              .collect(Collectors.toList());

        System.out.println(upperList);
    }
}

map()方法根据 Lambda 表达式String::toUpperCase将每个元素进行转换。

(二)reduce:元素累积操作

reduce 是一个用于对流中的元素进行累积操作的终端操作(Terminal Operation)。它的主要作用是将流中的元素组合成一个单个的值,通过指定的二元操作符(Binary Operator)来不断地将元素进行合并和累积。

reduce 方法的传参情况
两个参数

这种形式的 reduce 方法签名如下:

<U> U reduce(U identity, BinaryOperator<U> accumulator)
  • 参数说明
    • identity:初始值,也称为 “标识值”。它是一个与流中元素类型兼容的初始对象,在累积操作开始时作为起始点。如果流为空,reduce 操作会直接返回这个初始值。
    • accumulator:一个二元操作符,是一个 BinaryOperator<U> 类型的函数。它接受两个参数,第一个参数是累积结果(从初始值开始),第二个参数是流中的元素,用于将流中的元素逐步累积到结果中。
 一个参数
Optional<T> reduce(BinaryOperator<T> accumulator)
  • 参数说明
    • accumulator:同样是一个二元操作符,用于将流中的元素两两组合,逐步累积得到最终结果。
计算整数 List 中所有元素的乘积
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class ReduceExample {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);

        Optional<Integer> product = list.stream()
              .reduce((a, b) -> a * b);

        product.ifPresent(System.out::println);
    }
}

reduce()方法按照 Lambda 表达式(a, b) -> a * b对元素进行累积计算。

查找最大值或最小值
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;

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

        Optional<Integer> max = numbers.stream()
               .reduce((a, b) -> a > b? a : b);

        if (max.isPresent()) {
            System.out.println("Max: " + max.get());
        }
    }
}
连接字符串

对于一个包含字符串的 Stream,可以使用 reduce 来连接所有的字符串。

import java.util.Arrays;
import java.util.List;

public class ConcatenateStringsWithReduce {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("Hello", "World", "Java", "Stream");

        String result = words.stream()
               .reduce("", (accumulator, word) -> accumulator + word);

        System.out.println("Concatenated String: " + result);
    }
}

Lambda 表达式和 Stream API 的结合,为 Java 开发者提供了简洁高效的数据处理方式,熟练运用这些操作,能让代码更加优雅和易维护。

;