前言
A sequence of elements supporting sequential and parallel aggregate operations.
Java 8引入的Stream API是一种处理集合数据的高级抽象,它允许以声明式的方式对集合进行操作,使得代码更加简洁和易读。Stream不是数据结构,它不会存储数据,而是对数据源(如集合、数组等)进行一系列的操作,并返回一个新的Stream或一个最终结果。
Stream操作可以分为中间操作(Intermediate Operations)和终端操作(Terminal Operations)。中间操作会返回一个新的Stream,所以可以链式调用多个中间操作,如filter
、map
等;终端操作会触发Stream的执行并返回一个非Stream的结果,如forEach
、reduce
等。
基本语法
- 创建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方法示意图
对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中的元素收集到一个集合(如List
、Set
、Map
等)或者其他数据结构中。这是一个终端操作,它会终止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]
。
资料
- https://blogs.oracle.com/javamagazine/post/java-quiz-streams-collections-dropwhile-takewhile
- https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/stream/Stream.html
- https://dev.java/learn/api/streams/