Java Stream API:让集合操作更优雅的利器

121 阅读4分钟

前言

A sequence of elements supporting sequential and parallel aggregate operations.

Java 8引入的Stream API是一种处理集合数据的高级抽象,它允许以声明式的方式对集合进行操作,使得代码更加简洁和易读。Stream不是数据结构,它不会存储数据,而是对数据源(如集合、数组等)进行一系列的操作,并返回一个新的Stream或一个最终结果。

Stream操作可以分为中间操作(Intermediate Operations)和终端操作(Terminal Operations)。中间操作会返回一个新的Stream,所以可以链式调用多个中间操作,如filtermap等;终端操作会触发Stream的执行并返回一个非Stream的结果,如forEachreduce等。

基本语法

image

  • 创建Stream;
  • 转换Stream,每次转换原有Stream对象不改变,返回一个新的Stream对象
  • 对Stream进行聚合(Reduce)操作,获取想要的结果;

创建Stream

从集合创建

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

public class StreamDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("apple");
        list.add("banana");
        list.add("cherry");
        Stream<String> stream = list.stream();
        stream.forEach(System.out::println);
    }
}

首先创建了一个ArrayList,添加了三个水果名称。然后通过list.stream()方法创建了一个Stream对象,最后使用forEach终端操作来遍历并打印出每个元素。

从数组创建

import java.util.Arrays;
import java.util.stream.Stream;

public class StreamDemo {
    public static void main(String[] args) {
        String[] array = {"apple", "banana", "cherry"};
        Stream<String> stream = Arrays.stream(array);
        stream.forEach(System.out::println);
    }
}

定义了一个字符串数组,然后使用Arrays.stream(array)方法将数组转换为Stream,再通过forEach打印每个元素。

中间操作 - filter

用于过滤Stream中的元素,只保留满足指定条件的元素。

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

public class StreamDemo {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);
        numbers.add(5);
        Stream<Integer> stream = numbers.stream().filter(n -> n % 2 == 0);
        stream.forEach(System.out::println);
    }
}

创建了一个包含整数的ArrayList,然后通过stream().filter(n -> n % 2 == 0)操作,只保留能被2整除的元素,最后使用forEach打印出这些元素,这里会输出2和4。

中间操作 - map

map方法示意图 image

对Stream中的每个元素应用一个函数,将其转换为另一个元素。

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

public class StreamDemo {
    public static void main(String[] args) {
        List<String> fruits = new ArrayList<>();
        fruits.add("apple");
        fruits.add("banana");
        fruits.add("cherry");
        Stream<String> stream = fruits.stream().map(fruit -> fruit.toUpperCase());
        stream.forEach(System.out::println);
    }
}

创建了水果名称的列表,通过stream().map(fruit -> fruit.toUpperCase())操作将每个水果名称转换为大写形式,最后使用forEach打印出来,会输出APPLE、BANANA、CHERRY。

终端操作 - reduce

将Stream中的元素组合起来,得到一个单一的结果。

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

public class StreamDemo {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);
        numbers.add(5);
        int sum = numbers.stream().reduce(0, (a, b) -> a + b);
        System.out.println("Sum: " + sum);
    }
}

创建整数列表,通过reduce(0, (a, b) -> a + b)操作,从初始值0开始,将每个元素相加。这里会计算列表中所有整数的和,最后打印出总和,结果为15。

排序操作 - sorted

用于对Stream中的元素进行排序。可以根据元素的自然顺序(如果元素实现了Comparable接口)进行排序,也可以通过自定义比较器(Comparator)来指定排序规则。

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

public class StreamDemo {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(3);
        numbers.add(1);
        numbers.add(4);
        numbers.add(2);
        Stream<Integer> stream = numbers.stream().sorted();
        stream.forEach(System.out::println);
    }
}
  • 代码解释:首先创建了一个包含整数的ArrayList,元素顺序是无序的。然后使用stream().sorted()操作,按照整数的自然顺序(从小到大)对元素进行排序,最后通过forEach打印出排序后的元素,输出结果为1、2、3、4。

自定义比较器排序

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Stream;

public class StreamDemo {
    public static void main(String[] args) {
    List<String> fruits = new ArrayList<>();
        fruits.add("apple");
        fruits.add("banana");
        fruits.add("cherry");
        Stream<String> stream = fruits.stream().sorted(Comparator.comparing(String::length));
        stream.forEach(System.out::println);
    }
}

创建了一个水果名称列表,通过stream().sorted(Comparator.comparing(String::length))操作,根据字符串的长度对水果名称进行排序。在这里,先输出长度较短的单词,即apple,然后是cherry,最后是banana

去重操作 - distinct

用于去除Stream中的重复元素。它会根据元素的equals方法来判断元素是否相同。

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

public class StreamDemo {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(1);
        numbers.add(3);
        numbers.add(2);
        Stream<Integer> stream = numbers.stream().distinct();
        stream.forEach(System.out::println);
    }
}

创建包含整数的ArrayList,其中有重复的元素。使用stream().distinct()操作去除重复元素后,通过forEach打印出结果,输出为1、2、3。

收集操作 - collect

用于将Stream中的元素收集到一个集合(如ListSetMap等)或者其他数据结构中。这是一个终端操作,它会终止Stream并返回收集后的结果。

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

public class StreamDemo {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        List<Integer> collectedList = numbers.stream().collect(Collectors.toList());
        System.out.println(collectedList);
    }
}

创建一个整数ArrayList,然后使用stream().collect(Collectors.toList())操作将Stream中的元素收集到一个新的List中,并打印这个新的List,输出为[1, 2, 3]

资料