中间操作、终止操作
只有中间操作没有终止操作的话,这些操作不会立即执行,也就是不会立即对元素进行处理,而是返回一个新的 Stream 对象,这个新的 Stream 对象会在遇到终止操作时才会执行中间操作中定义的逻辑。
简单来说,中间操作返回的是一个“惰性求值”的 Stream 对象,只有在遇到终止操作时才会触发实际的计算,这种方式可以提高计算效率。
中间操作和终止操作分别有哪些?
- 中间操作:
- filter、limit、skip、distinct、sorted
- map
- parallel
- 终止操作
- forEach、sum、min、max、count、average
- anyMatch、allMatch、noneMatch
- reduce、collect
filter
使用 filter 方法可以根据指定的条件过滤出符合条件的元素。
ArrayList<String> list = new ArrayList<>();
list.add("《日日是好日》");
list.add("《三国演义》");
list.add("《孙子兵法》");
list.add("《小狗钱钱》");
Stream<String> stream = list.stream().filter(element -> element.contains("日"));
stream.forEach(System.out::println);
// 输出:《日日是好日》
limit
limit 方法可以截取指定数量的元素,返回一个新的流。
List<Integer> numbers = Arrays.asList(1, 2, 3, 2, 5);
Stream<Integer> distinct = numbers.stream().limit(3);
distinct.forEach(System.out::println);
// 输出:
// 1
// 2
// 3
skip
skip 方法可以跳过指定数量的元素。
List<Integer> numbers = Arrays.asList(8, 2, 3, 2, 5);
Stream<Integer> skip = numbers.stream().skip(2);
skip.forEach(System.out::println);
// 输出:
// 3
// 2
// 5
distinct
使用 distinct 方法可以去除流中重复的元素。
List<Integer> numbers = Arrays.asList(1, 2, 3, 2, 5);
Stream<Integer> distinctNumbers = numbers.stream().distinct();
distinctNumbers.forEach(System.out::println);
// 输出:
// 1
// 2
// 3
// 5
sorted
使用 sorted 方法可以对流中的元素进行排序。
int[] numbers = {5, 8, 1, 3, 9};
IntStream sortedNumbers = Arrays.stream(numbers).sorted();
sortedNumbers.forEach(System.out::println);
// 输出:
// 1
// 3
// 5
// 8
// 9
对流中的对象进行排序,需要实现 Comparable 接口或者使用 Comparator 接口。
1、实现 Comparable 接口
package com.qf.cmf.javabase.stream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
class Person implements Comparable<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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Person o) {
return Integer.compare(this.age, o.age);
}
}
public class StreamSortedExample {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("A", 20));
people.add(new Person("B", 25));
people.add(new Person("C", 18));
people.add(new Person("D", 30));
// 使用Comparable接口进行排序
Collections.sort(people);
System.out.println(people);
}
}
// 输出:
// [Person{name='C', age=18}, Person{name='A', age=20}, Person{name='B', age=25}, Person{name='D', age=30}]
2、 Comparator 接口
package com.qf.cmf.javabase.stream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class StreamSortedExample {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("A", 20));
people.add(new Person("C", 25));
people.add(new Person("B", 18));
people.add(new Person("D", 30));
// 使用Comparator接口进行排序
people.stream().sorted(Comparator.comparing(Person::getName)).forEach(p -> System.out.println(p.getName() + " " + p.getAge()));
}
}
// 输出:
// A 20
// B 18
// C 25
// D 30
map
使用 map 方法可以将一个流中的元素按照指定的方式进行转换,生产一个新的流。
ArrayList<String> list = new ArrayList<>();
list.add("《日日是好日》");
list.add("《三国演义》");
list.add("《孙子兵法》");
list.add("《小狗钱钱》");
Stream<Integer> stream = list.stream().map(String::length);
stream.forEach(System.out::println);
// 输出:
// 7
// 6
// 6
// 6
forEach
forEach 方法可以用来遍历 Stream 中的每一个元素,它的语法如下:
void forEach(Consumer<? super T> action)
其中,action 表示对每个元素要执行的操作,它是一个 Consumer 接口的实例。
List<String> list = Arrays.asList("Java", "Python", "JavaScript", "C++");
// 使用 forEach() 方法遍历 Stream 中的每一个元素
list.stream().forEach(System.out::println);
// 输出:
// Java
// Python
// JavaScript
// C++
sum、min、max、count、average
使用 sum、min、max、count、average 等方法可以对流中的元素进行统计
sum 求和
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream().mapToInt(Integer::intValue).sum();
System.out.println(sum); // 输出 15
min 求最小值
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int min = numbers.stream().mapToInt(Integer::intValue).min().orElse(0);
System.out.println(min); // 输出 1
求最大值
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int max = numbers.stream().mapToInt(Integer::intValue).max().orElse(0);
System.out.println(max); // 输出 5
统计元素个数
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
long count = numbers.stream().count();
System.out.println(count); // 输出 5
求平均值
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
double average = numbers.stream().mapToInt(Integer::intValue).average().orElse(0);
System.out.println(average); // 输出 3.0
anyMatch、allMatch、noneMatch
使用 anyMatch、allMatch、noneMatch 等方法可以判断流中的元素是否符合指定的条件。
anyMatch:返回一个 boolean 值,表示 Stream 中是否存在至少一个元素符合指定的条件。
allMatch:返回一个 boolean 值,表示 Stream 中的所有元素是否都符合指定的条件。
noneMatch:返回一个 boolean 值,表示 Stream 中是否不存在任何一个元素符合指定的条件。
ArrayList<String> list = new ArrayList<>();
list.add("《日日是好日》");
list.add("《三国演义》");
list.add("《孙子兵法》");
list.add("《小狗钱钱》");
boolean anyMatchFlag = list.stream().anyMatch(element -> element.contains("技"));
boolean allMatchFlag = list.stream().allMatch(element -> element.length() > 1);
boolean noneMatchFlag = list.stream().noneMatch(element -> element.endsWith("术"));
// 输出
// false
// true
// true
reduce
reduce 函数的语法如下:
T reduce(BinaryOperator<T> accumulator)
使用 reduce 方法可以将流中的元素按照指定的方式进行归约,生成一个新的值。
Integer[] ints = {0, 1, 2, 3};
List<Integer> list = Arrays.asList(ints);
Optional<Integer> optional = list.stream().reduce((a, b) -> a + b);
Optional<Integer> optional1 = list.stream().reduce(Integer::sum);
System.out.println(optional.orElse(0));
System.out.println(optional1.orElse(0));
// 输出:
// 6
// 6
int reduce = list.stream().reduce(6, (a, b) -> a + b);
System.out.println(reduce);
int reduce1 = list.stream().reduce(6, Integer::sum);
System.out.println(reduce1);
// 输出:
// 12
// 12
reduce 可以设定初始值,如果设定了的话初始值也会加上运算。
collect
使用 collect 方法可以将流中的元素收集到一个集合中。
ArrayList<String> list = new ArrayList<>();
list.add("《日日是好日》");
list.add("《三国演义》");
list.add("《孙子兵法》");
list.add("《小狗钱钱》");
List<Integer> list1 = list.stream().map(String::length).collect(Collectors.toList());
List<String> list2 = list.stream().collect(Collectors.toCollection(ArrayList::new));
List<String> list3 = list.stream().collect(Collectors.toList());
String list4 = list.stream().collect(Collectors.joining(", ")).toString();
System.out.println(list1);
System.out.println(list2);
System.out.println(list3);
System.out.println(list4);
// 输出:
// [7, 6, 6, 6]
// [《日日是好日》, 《三国演义》, 《孙子兵法》, 《小狗钱钱》]
// [《日日是好日》, 《三国演义》, 《孙子兵法》, 《小狗钱钱》]
// 《日日是好日》, 《三国演义》, 《孙子兵法》, 《小狗钱钱》
总结
Stream 是非常强大的,感兴趣可以深入去学习。
“行动是治愈恐惧的良药,而犹豫拖延将不断滋养恐惧。"