Stream
流是Java 8中引入的一个新特性,它允许以声明性方式处理数据,如过滤、映射、排序等。常用的Stream
流方法包括filter
、map
、sorted
、limit
、skip
、reduce
、collect
、forEach
、findFirst
和count
等,这些方法可以根据具体的需求进行组合使用,以实现复杂的流式处理逻辑,但在使用的时候也要注意线程安全问题
Stream
流的使用步骤如下:
- 准备数据源:可以使用集合、数组等作为数据源
- 获取流对象:通过调用集合、数组等对象的
stream()
方法来获取流对象- 中间操作:使用中间操作来对流中的元素进行
过滤(filter)
、映射(map)
、排序(sorted)
等操作- 终结操作:终结操作是用来结束流并收集操作结果的,常用的终结操作包括
collect()
、forEach()
等
stream()
方法从集合(如List
、Set
、Map
)创建Stream
parallelStream()
将Stream
转换为并行流,实现并行处理,提高处理速度// 使用stream()方法从集合(如List、Set、Map)创建Stream
List<String> strings = Arrays.asList("Hello", "World", "Stream1111", "API11111");
Stream<String> stringStream = strings.stream();
//使用parallelStream():将Stream转换为并行流,实现并行处理,提高处理速度
long count = strings.parallelStream()
.filter(c -> c.length() > 5)
.count();
System.out.println(count); // [2]
Arrays.stream()
方法从数组创建流Stream.of(array)
可以获取数组对应的流// 使用Arrays.stream()方法从数组创建流
int[] numbers = {1, 2, 3, 4, 5};
IntStream stream = Arrays.stream(numbers);
// 使用静态方法Stream.of(array)可以获取数组对应的流
Stream<String> stream = Stream.of(array);
filter()
// filter方法用于过滤出满足特定条件的元素,返回一个包含满足条件的元素的新流
// 例如:以下代码将过滤出列表中所有的偶数
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
Stream<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0);// [2 4 6 8]
map()
// map方法用于将流中的每个元素映射到另一个对象,返回一个由映射结果组成的流
// 例如:以下代码将字符串列表中的每个字符串转换成小写字母
List<String> words = Arrays.asList("Hello", "World", "Stream", "API");
List<String> lowercaseWords = words.stream()
.map(String::toLowerCase)
.collect(Collectors.toList());
System.out.println(lowercaseWords); // [hello, world, stream, api]
sorted()
// sorted方法用于对流中的元素进行排序,返回一个按指定顺序排序的新流
// 例如:以下代码将列表中的字符串按照字母顺序排序
List<String> words = Arrays.asList("Hello", "World", "Stream", "API");
List<String> sortedWords = words.stream()
.sorted()
.collect(Collectors.toList());
System.out.println(sortedWords); // [API, Hello, Stream, World]
limit()
// limit方法用于获取流中的前几个元素,返回一个包含指定数量的元素的新流
// 例如:以下代码将获取列表中的前三个元素
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
List<Integer> firstThreeNumbers = numbers.stream()
.limit(3)
.collect(Collectors.toList());
System.out.println(firstThreeNumbers); // [1, 2, 3]
skip()
// skip方法用于跳过流中的前几个元素,返回一个新的流,该流不包含被跳过的元素
// 例如:以下代码将跳过列表中的前两个元素
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
List<Integer> skippedNumbers = numbers.stream()
.skip(2)
.collect(Collectors.toList());
System.out.println(skippedNumbers); // [3, 4, 5, 6, 7, 8, 9]
reduce()
// reduce操作是对Stream中的元素进行归约操作,通常用于计算总和、平均值等聚合数据
// reduce操作需要一个BinaryOperator作为参数,用于指定如何将两个元素进行归约
int sum = Arrays.asList(1, 2, 3, 4, 5).stream()
.reduce(0, Integer::sum); // 0是初始值,Integer::sum是归约操作
System.out.println(sum); // [15]
forEach()
// 使用lambda表达式打印每个字符串到控制台
List<String> strings = Arrays.asList("Java", "Python", "C++", "JavaScript");
List<String> collectedStrings = strings.stream()
.filter(str -> str.startsWith("J"))
.forEach(System.out::print); // [Java, JavaScript]
collect()
// collect操作用于将Stream中的元素收集到一个集合中
// 通过collect操作,我们可以将Stream中的元素汇总到List、Set等集合类型中
List<String> strings = Arrays.asList("Java", "Python", "C++", "JavaScript");
List<String> collectedStrings = strings.stream()
.filter(str -> str.startsWith("J"))
.collect(Collectors.toList());
System.out.println(collectedStrings); // [Java, JavaScript]
count()
long count = Arrays.asList(1, 2, 3, 4, 5).stream()
.count(); // 计算Stream中元素的数量
System.out.println(count); // [5]
// toList()方法将流中的元素收集到一个List中
List<String> words = Arrays.asList("Java", "Stream", "API");
List<String> collectedList = words.stream()
.collect(Collectors.toList());
// 将流中的元素收集到 List 中
System.out.println(collectedList); // [Java, Stream, API]
// toSet()方法将流中的元素收集到一个Set中
List<String> words = Arrays.asList("Java", "Stream", "API");
Set<String> collectedSet = words.stream()
.collect(Collectors.toSet());
// 将流中的元素收集到 Set 中
System.out.println(collectedSet); // [Java, Stream, API](无序)
// toMap()方法将流中的元素按照键值对的方式收集到一个Map中
List<String> words = Arrays.asList("Java", "Stream", "API");
Map<Integer, String> collectedMap = words.stream()
.collect(Collectors.toMap(String::length, s -> s));
// 将流中的元素按照长度作为键收集到 Map 中
System.out.println(collectedMap); // {4=Java, 6=Stream, 3=API}
// 注意: 这种时候一定要进行去重操作,不然会报错,这里如果出现了重复就保留之前的
allUserList.stream()
.collect(Collectors.toMap( CompanyUserListDO::getName,
CompanyUserListDO::getCloudUserId,
(existing, replacement) -> existing))
// joining()方法将流中的元素连接成一个字符串
List<String> words = Arrays.asList("Java", "Stream", "API");
String concatenated = words.stream()
.collect(Collectors.joining(", "));
// 将流中的元素用逗号连接成字符串
System.out.println(concatenated); // [Java, Stream, API]
// groupingBy()方法按照某个分类器对流中的元素进行分组,生成一个Map
List<String> words = Arrays.asList("Java", "Stream", "API");
Map<Integer, List<String>> groupedByLength = words.stream()
.collect(Collectors.groupingBy(String::length));
// 按照字符串长度对流中的元素进行分组
System.out.println(groupedByLength); // {3=[Java], 5=[Stream], 3=[API]}
// partitioningBy()方法根据某个条件对流中的元素进行分区,生成一个Map
List<String> words = Arrays.asList("Java", "Stream", "API");
Map<Boolean, List<String>> partitionedByLength = words.stream()
.collect(Collectors.partitioningBy(s -> s.length() > 4));
// 根据字符串长度是否大于4对流中的元素进行分区
System.out.println(partitionedByLength); // 输出:{false=[Java, API], true=[S
ThreadUnsafeStreamExample_A
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadUnsafeStreamExample_A {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
// 并行流
int sum = numbers.parallelStream()
.mapToInt(n -> n) // 映射为整数流
.sum(); // 求和
System.out.println("Sum: " + sum); // 输出:Sum: 45
}
}
在上述代码中,我们使用并行流对一个包含9
个整数的列表进行求和操作,由于使用了并行流,求和操作会在多个线程上同时进行,如果sum()
方法内部存在线程不安全问题,那么最终的结果可能会出现错误。
为了解决线程不安全问题,可以使用AtomicInteger
类来保证线程安全地累加求和的结果。下面是使用AtomicInteger
的示例代码:
ThreadSafeStreamExample_B
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadSafeStreamExample_B {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
// 并行流
AtomicInteger sum = new AtomicInteger(0);
numbers.parallelStream()
.mapToInt(n -> n) // 映射为整数流
.forEach(n -> sum.addAndGet(n)); // 累加求和的结果
System.out.println("Sum: " + sum.get()); // Sum: 45
}
}
我们使用AtomicInteger
来累加求和的结果,由于AtomicInteger
是线程安全的,因此可以在多个线程上同时进行累加操作,而不会出现线程不安全问题,最终的结果将正确地输出为45
。