一、中间操作
中间操作是返回一个新的流,并在返回的流中包含所有之前的操作结果。它们总是延迟计算,这意味着它们只会在终止操作时执行,这样可以最大限度地优化资源使用。
1. filter(过滤)
filter()
方法接受一个谓词(一个返回boolean值的函数),并返回一个流,其中仅包含通过该谓词的元素。
eg:从一个数组中筛选出长度大于5的元素。
@Test
public void testFilter() {
List<String> names = Arrays.asList("Chengdu", "Shanghai", "Changsha", "Wuhan", "Hangzhou");
List<String> collect = names.stream().filter(item -> item.length() > 5).collect(Collectors.toList());
System.out.println(collect);
}
2. map(转换)
map()
方法可将一个流的元素转换为另一个流。它接受一个函数,该函数映射流中的每个元素到另一个元素。
eg:对数字列表中的每个元素进行乘以 2 的操作,并将操作后的结果保存到新的列表中。
@Test
public void testMap() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> collect = numbers.stream().map(n -> {
n = n * 2;
return n;
}).collect(Collectors.toList());
for (Integer integer : collect) {
System.out.println("integer = " + integer);
}
}
eg:将结果转换为Map。
@Test
public void testMapToMap() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Map<Byte, Integer> collect = numbers.stream().collect(Collectors.toMap(Integer::byteValue, item -> item * 2, (val1, val2) -> val2));
for (Map.Entry<Byte, Integer> byteIntegerEntry : collect.entrySet()) {
Byte key = byteIntegerEntry.getKey();
System.out.println("key = " + key + ",Value = " + byteIntegerEntry.getValue());
}
}
- 首先创建了一个包含数字 1~5 的列表。然后利用
stream()
方法将列表转换成 Stream 对象。 - 接下来调用
collect(Collectors.toMap(…))
方法将 Stream 转换成Map<Byte, Integer>
。 - 在
toMap ()
方法中,以每个整数的字节值为键,该整数乘以 2 为值,当遇到重复的键时取最后一个值。(这里实际上可以用任何能区分不同键的方式作为第一个参数,而不一定是Integer::byteValue
) - 最后,在 for 循环中遍历了这个 Map 并打印出每个键值对的内容。
3. sorted(排序)
sorted()
方法可对流进行排序。它可以接受一个Comparator参数,也可以使用自然排序Ordering.natural()
。默认排序是按升序排序。
eg:对数组元素排序。
@Test
public void testSorted() {
int[] numbers = {5, 2, 8, 3, 7};
int[] sortedNumbers = Arrays.stream(numbers).sorted().toArray();
System.out.println(Arrays.toString(sortedNumbers));
}
- 首先创建了一个包含整数的数组numbers。
- 然后使用
Arrays.stream()
方法将其转化为一个IntStream流。 - 接下来使用
sorted()
方法对流中的元素进行排序操作,返回一个新的排序后的IntStream流。 - 最后,使用
toArray()
方法将排序后的结果转换为一个新的int类型数组sortedNumbers,并使用Arrays.toString()
方法将结果输出到控制台。
4. distinct(去重)
distinct()
方法从流中返回所有不同的元素。在内部,它使用equals()
方法来比较元素是否相同。因此,我们需要确保equals()
方法已正确实现。
eg:去除list集合中重复的元素。
@Test
public void testDistinct() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 2, 1);
List<Integer> collect = numbers.stream().distinct().collect(Collectors.toList());
System.out.println(collect);
}
- 首先创建了一个包含整数的List集合numbers,其中包含了若干个重复的整数。
- 接下来使用
Stream()
方法将其转化为一个Stream流。使用distinct()
方法对流中的元素进行去重操作,返回一个新的不包含重复元素的Stream流collect。 - 最后使用
collect()
方法将去重后的结果转换成一个List集合,并使用System.out.println()
方法输出到控制台。
使用Stream流中的distinct()
方法可以快速地对集合中的重复元素进行去重处理。在这段代码中,集合中的元素都是整数,使用distinct()
方法去除了所有重复的整数,返回一个新的元素不重复且顺序不变的List集合。
5. limit(限制)
limit()
方法可以将流限制为指定的元素数。
eg:输出数组中前三个数。
@Test
public void testLimit() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
List<Integer> collect = numbers.stream().limit(3).collect(Collectors.toList());
System.out.println(collect);
}
- 首先创建了一个包含整数的List集合numbers,其中包含了10个整数。
- 接下来使用
Stream()
方法将其转化为一个Stream流。使用limit()
方法对流中的元素进行限制操作,仅保留前3个元素,返回一个新的只包含前3个元素的Stream流collect。 - 最后使用
collect()
方法将限制操作后的结果转化为一个新的List集合,并使用System.out.println()
方法输出到控制台。
6. skip(跳过)
skip()
方法可跳过前N个元素。
eg:跳过数组的前三个数。
@Test
public void testSkip() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
List<Integer> collect = numbers.stream().skip(3).collect(Collectors.toList());
System.out.println(collect);
}
- 首先创建了一个包含整数的List集合numbers,其中包含了5个整数。
- 接下来使用
Stream()
方法将其转化为一个Stream流。使用skip()
方法对流中的元素进行跳过操作,跳过前2个元素,返回一个新的不包含前2个元素的Stream流collect。 - 最后使用
collect()
方法将跳过操作后的结果转化为一个新的List集合,并使用System.out.println()
方法输出到控制台。
7. peek(展示)
peek()
方法可以用于在Stream流中获取元素同时执行一些操作,如打印、调试、观察等。通常会与其他的方法联合使用。
eg:输出元素。
@Test
public void testPeek() {
List<String> names = Arrays.asList("Chengdu", "Shanghai", "Changsha", "Guangzhou");
List<String> filteredNames = names.stream()
.peek(System.out::println)
.filter(name -> name.startsWith("C"))
.peek(name -> System.out.println("Filtered value: " + name))
.collect(Collectors.toList());
System.out.println("-----------------------------------------------------------------");
System.out.println(filteredNames);
}
- 首先创建了一个列表 names 包含四个字符串元素,使用流式操作处理这个列表。
- 然后使用
peek()
方法将每个元素打印到控制台,使用filter()
方法过滤掉不符合条件的元素,即不以字母 C 开头的字符串。 - 接下来再次使用
peek()
方法将符合条件的字符串打印到控制台,以便验证过滤操作的效果。 - 最后使用
collect()
方法将符合条件的字符串收集到一个新的列表 filteredNames 中,并输出该列表。
二、终止操作
终止操作返回一个结果或副作用(例如:显示控制台输出),并将流关闭。
1. forEach(遍历)
forEach()
方法可将给定的方法应用于流中的每个元素。该方法是一种消费流的方式,不会返回值。
eg:数组元素遍历。
@Test
public void testForEach() {
List<String> names = Arrays.asList("Chengdu", "Shanghai", "Wuhan", "Changsha");
names.stream().forEach(System.out::println);
}
- 创建了一个包含四个字符串元素的列表 names。
- 使用流式操作将每个元素打印到控制台。具体来说,它使用
forEach()
方法遍历列表中的所有元素,并对每个元素执行打印操作。
2. collect(收集)
collect()
方法可以将流中的元素收集到一个集合中。一般与其他方法配合使用。
eg:收集数组中能被25整除的数。
@Test
public void testCollect() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0).collect(Collectors.toList());
System.out.println(evenNumbers);
}
- 首先创建了一个包含整数的列表 numbers,使用流式操作筛选出所有偶数。
- 然后将它们收集到一个新的列表 evenNumbers 中,并打印输出。
这里使用了 filter() 方法过滤掉所有奇数元素,只保留所有偶数元素,并使用 collect()
方法将它们收集到一个新的列表 evenNumbers 中。只有偶数元素被保留在了新列表 evenNumbers 中,而奇数元素全部被过滤掉了。而且,在筛选偶数元素时,使用了 lambda 表达式 n -> n % 2 == 0
,其中 % 表示取模操作,判断当前数是否为偶数。如果 n % 2
的结果是 0,就把 n 这个数保留下来,否则就过滤掉。
3. count(计数)
count()
方法可以返回流中的元素数。
eg:计算数组元素个数。
@Test
public void testCount() {
List<String> names = Arrays.asList("Chengdu", "Guangzhou", "Wuhan", "Changsha");
long count = names.stream().count();
System.out.println(count);
}
- 首先创建了一个包含四个字符串元素的列表 names,使用流式操作计算出它包含的元素数量(即列表大小),并将该数量打印到控制台。
这里使用了 count()
方法统计列表中元素的个数。count()
方法返回的是一个 long 类型的值,表示列表中元素的个数。因为列表 names 包含了四个元素,所以 count()
方法返回值为 4,最终被打印输出到了控制台。
4. reduce(聚合)
reduce()
方法可以将流元素聚合为单个结果。它接受一个BinaryOperator参数作为累加器。
eg:计算数组元素的和。
@Test
public void testReduce() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> sum = numbers.stream().reduce((a, b) -> a + b);
System.out.println(sum);
}
- 首先创建了一个包含整数的列表 numbers,使用流式操作将它们累加起来得到总和,并将结果打印输出。
这里使用了 reduce()
方法对列表中的所有元素进行累加操作。reduce()
方法接收一个 BinaryOperator 函数作为参数,用于指定如何处理相邻的两个元素并返回一个新的结果值。reduce()
方法返回的是一个 Optional 类型的值,表示结果可能存在也可能不存在(例如当列表为空时)。由于列表 numbers 包含 1 到 5 共五个元素,因此 reduce()
方法的操作过程如下:
1 + 2 = 3
3 + 3 = 6
6 + 4 = 10
10 + 5 = 15
最终得到的结果 15 被包装成 Optional 类型的对象并打印输出到控制台。
5. anyMatch(任意匹配)
anyMatch()
方法如果至少有一个元素与给定的谓词匹配,则返回true。
eg:判断数组元素中是否有以W开头的,有返回true,无返回false。
@Test
public void anyMatch() {
List<String> names = Arrays.asList("Chengdu", "Guangzhou", "Wuhan", "Changsha");
boolean anyStartsWithB = names.stream().anyMatch(name -> name.startsWith("W"));
System.out.println(anyStartsWithB);
}
- 首先创建了一个包含四个字符串元素的列表 names,使用流式操作检查其中是否有任意一个元素以字母 “W” 开头,并将检查结果(布尔值)打印输出。
这里使用了 anyMatch()
方法匹配列表中的所有元素,并依次对每个元素执行指定的谓词操作(这里是以 “W” 开头),只要有一个元素符合条件,就返回 true,否则返回 false。列表 names 中包含了一个以字母 “W” 开头的元素 “Wuhan”,因此 anyMatch()
方法返回 true,最终被打印输出到了控制台。
6. oneMatch(无匹配)
noneMatch()
方法,如果没有任何元素与给定谓词匹配,则返回true。
eg:判断数组元素中是否有以H开头的,无返回true,有返回false。
@Test
public void testToneMatch() {
List<String> names = Arrays.asList("Chengdu", "Guangzhou", "Wuhan", "Changsha");
boolean noneStartsWithB = names.stream().noneMatch(name -> name.startsWith("H"));
System.out.println(noneStartsWithB);
}
- 首先创建了一个包含四个字符串元素的列表 names,使用流式操作检查其中是否没有任意一个元素以字母 “H” 开头,并将检查结果(布尔值)打印输出。
这里使用了 noneMatch()
方法匹配列表中的所有元素,并依次对每个元素执行指定的谓词操作(这里是以 “H” 开头),只有当所有元素都不符合条件时,才返回 true,否则返回 false。列表 names 中不包含任何一个以字母 “H” 开头的元素,因此 noneMatch()
方法返回 true,最终被打印输出到了控制台。