大家好,我是Leo🫣🫣🫣,上周一直在忙于Spring系列文章的更迭,一直没有时间系列去更其他系列博文,也是耽搁了很久,今天1024,Leo提前祝大家节日快乐,今天我们主要学习一下关于JavaStream流相关的知识点,好了,话不多说让我们开始吧😎😎😎。
Java 流(Stream)是一连串的元素序列,可以进行各种操作以实现数据的转换和处理。流式编程的概念基于函数式编程的思想,旨在简化代码,提高可读性和可维护性。
Java Stream 的主要作用有以下几个方面:
我们首先创建一个演员类。
package com.trs.stream;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author : Leo
* @version 1.0
* @date 2023-10-24 9:42
* @description : 示例
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Actor {
/*编写一个演员类 有 演员id演员名称和演员年龄 演员作品 */
private Integer id;
private String name;
private Integer age;
private String works;
}
基于这个类,我们初始化一个演员集合:
package com.trs.stream;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
/**
* @author : Leo
* @version 1.0
* @date 2023-10-24 9:42
* @description : 示例
*/
public class StreamTest01 {
public static final List<Actor> actorList =
Arrays.asList( new Actor(1001, "张三", 30, "演员"),
new Actor(1002, "李四", 70, "演员"),
new Actor(1003, "王五", 40, "演员"),
new Actor(1004, "赵六", 53, "演员"),
new Actor(1005, "莉莉", 35, "演员"),
new Actor(1006, "杨晓雪", 12, "演员"),
new Actor(1007, "李师傅", 55, "演员"),
new Actor(1008, "王胖子", 40, "演员"),
new Actor(1009, "齐肩发", 45, "演员"));
}
/**
* 用于测试: 使用Java8之前的做法
*/
@Test
public void test1() {
List<Actor> ageList = new ArrayList<>();
//筛选演员年龄小于40岁的
for (Actor actor : actorList) {
if (actor.getAge() <40){
ageList.add(actor);
}
}
//按照升序进行排序
List<String> lowActoresName = new ArrayList<>();
Collections.sort(ageList, new Comparator<Actor>() {
public int compare(Actor c1, Actor c2) {
return Integer.compare(c1.getId(), c2.getId());
}
});
//存入string列表
for (Actor d : ageList) {
lowActoresName.add(d.getName());
}
//输出
for (Actor lowCaloricActor : ageList) {
System.out.println(lowCaloricActor);
}
}
对应输出结果如下,张三,莉莉,杨晓雪,符合我们的预期:
/**
* 用于测试: 流式编程
*/
@Test
public void test2() {
actorList.stream()
// 过滤演员年龄小于40的
.filter(c -> c.getAge() <40)
// 用id进行排序
.sorted(comparing(Actor::getId))
// 合并map,拿到名字相同的去作用于各个演员
.map(Actor::getName)
// 转为list
.collect(toList())
// 输入
.forEach(System.out::println);
}
结果同样符合我们的预期
Stream(流)是 Java 8 引入的一个新的抽象概念,它代表着一种处理数据的序列。简单来说,Stream 是一系列元素的集合,这些元素可以是集合、数组、I/O 资源或者其他数据源。
Stream API 提供了丰富的操作方法,可以对 Stream 中的元素进行各种转换、过滤、映射、聚合等操作,从而实现对数据的处理和操作。Stream API 的设计目标是提供一种高效、可扩展和易于使用的方式来处理大量的数据。
Stream 具有以下几个关键特点:
通过使用 Stream,我们可以使用简洁、函数式的方式处理数据。相比传统的循环和条件语句,Stream 提供了更高层次的抽象,使代码更具可读性、简洁性和可维护性。它是一种强大的工具,可以帮助我们更有效地处理和操作集合数据。
从集合创建:我们可以通过调用集合的 stream()
方法来创建一个 Stream 对象。例如:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = numbers.stream();
从数组创建:Java 8 引入了 Arrays
类的 stream()
方法,我们可以使用它来创建一个 Stream 对象。例如:
String[] names = {"Alice", "Bob", "Carol"};
Stream<String> stream = Arrays.stream(names);
通过 Stream.of() 创建:我们可以使用 Stream.of()
方法直接将一组元素转换为 Stream 对象。例如:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
通过 Stream.builder() 创建:如果我们不确定要添加多少个元素到 Stream 中,可以使用 Stream.builder()
创建一个 Stream.Builder 对象,并使用其 add()
方法来逐个添加元素,最后调用 build()
方法生成 Stream 对象。例如:
Stream.Builder<String> builder = Stream.builder();
builder.add("Apple");
builder.add("Banana");
builder.add("Cherry");
Stream<String> stream = builder.build();
从 I/O 资源创建:Java 8 引入了一些新的 I/O 类(如 BufferedReader
、Files
等),它们提供了很多方法来读取文件、网络流等数据。这些方法通常返回一个 Stream 对象,可以直接使用。例如:
Path path = Paths.get("data.txt");
try (Stream<String> stream = Files.lines(path)) {
// 使用 stream 处理数据
} catch (IOException e) {
e.printStackTrace();
}
通过生成器创建:除了从现有的数据源创建 Stream,我们还可以使用生成器来生成元素。Java 8 中提供了 Stream.generate()
方法和 Stream.iterate()
方法来创建无限 Stream。例如:
Stream<Integer> stream = Stream.generate(() -> 0); // 创建一个无限流,每个元素都是 0
Stream<Integer> stream = Stream.iterate(0, n -> n + 1); // 创建一个无限流,从 0 开始递增
需要注意的是,Stream 对象是一种一次性使用的对象,它只能被消费一次。一旦对 Stream 执行了终止操作(如收集结果、遍历元素),Stream 就会被关闭,后续无法再使用。因此,在使用 Stream 时,需要根据需要重新创建新的 Stream 对象。
过滤(Filter):filter()
方法接受一个 Predicate 函数作为参数,用于过滤 Stream 中的元素。只有满足 Predicate 条件的元素会被保留下来。例如:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> filteredStream = stream.filter(n -> n % 2 == 0); // 过滤出偶数
映射(Map):map()
方法接受一个 Function 函数作为参数,用于对 Stream 中的元素进行映射转换。对每个元素应用函数后的结果会构成一个新的 Stream。例如:
Stream<String> stream = Stream.of("apple", "banana", "cherry");
Stream<Integer> mappedStream = stream.map(s -> s.length()); // 映射为单词长度`
扁平映射(FlatMap):flatMap()
方法类似于 map()
方法,不同之处在于它可以将每个元素映射为一个流,并将所有流连接成一个流。这主要用于解决嵌套集合的情况。例如:
List<List<Integer>> nestedList = Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4),
Arrays.asList(5, 6)
);
Stream<Integer> flattenedStream = nestedList.stream().flatMap(List::stream); // 扁平化为一个流
截断(Limit):limit()
方法可以限制 Stream 的大小,只保留前 n 个元素。例如:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> limitedStream = stream.limit(3); // 只保留前 3 个元素
跳过(Skip):skip()
方法可以跳过 Stream 中的前 n 个元素,返回剩下的元素组成的新 Stream。例如:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);java
Stream<Integer> skippedStream = stream.skip(2); // 跳过前 2 个元素
排序(Sorted):sorted()
方法用于对 Stream 中的元素进行排序,默认是自然顺序排序。还可以提供自定义的 Comparator 参数来指定排序规则。例如:
Stream<Integer> stream = Stream.of(5, 2, 4, 1, 3);
Stream<Integer> sortedStream = stream.sorted(); // 自然顺序排序
去重(Distinct):distinct()
方法用于去除 Stream 中的重复元素,根据元素的 equals()
和 hashCode()
方法来判断是否重复。例如:
Stream<Integer> stream = Stream.of(1, 2, 2, 3, 3, 3);
Stream<Integer> distinctStream = stream.distinct(); // 去重
汇总(Collect):collect()
方法用于将 Stream 中的元素收集到结果容器中,如 List、Set、Map 等。可以使用预定义的 Collectors 类提供的工厂方法来创建收集器,也可以自定义收集器。例如:
Stream<String> stream = Stream.of("apple", "banana", "cherry");
List<String> collectedList = stream.collect(Collectors.toList()); // 收集为 List
归约(Reduce):reduce()
方法用于将 Stream 中的元素依次进行二元操作,得到一个最终的结果。它接受一个初始值和一个 BinaryOperator 函数作为参数。例如:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Optional<Integer> sum = stream.reduce((a, b) -> a + b); // 对所有元素求和
统计(Summary Statistics):summaryStatistics()
方法可以从 Stream 中获取一些常用的统计信息,如元素个数、最小值、最大值、总和和平均值。例如:
IntStream stream = IntStream.of(1, 2, 3, 4, 5);
IntSummaryStatistics stats = stream.summaryStatistics();
System.out.println("Count: " + stats.getCount());
System.out.println("Min: " + stats.getMin());
System.out.println("Max: " + stats.getMax());
System.out.println("Sum: " + stats.getSum());
System.out.println("Average: " + stats.getAverage());
以上只是 Stream API 提供的一部分常用操作方法,还有许多其他操作方法,如匹配(Match)、查找(Find)、遍历(ForEach)等。
中间操作方法分类:
终端操作方法分类:
中间操作代码实例详解
1、filter(): 返回结果生成新的流中只包含满足筛选条件的数据。
// 1、filter,返回大于2的元素集合
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> result = nums.stream().filter(n -> n > 2).collect(Collectors.toList());
System.out.println(result);
运行结果:
2、map():将流中的元素进行再次加工形成一个新流,流中的每一个元素映射为另外的元素。
// 2、map:返回元素的大写类型和哈希值
List<String> mzc = Arrays.asList("L", "e", "o");
List<String> mzcUpperCase = mzc.stream().
map(n -> n.toUpperCase()).
collect(Collectors.toList());
List<Integer> mzcHashCode = mzc.stream().map(n -> n.hashCode()).collect(Collectors.toList());
System.out.println("mzcUpperCase:"+mzcUpperCase+" ----- mzcHashCode:"+mzcHashCode);
运行结果:
示例场景:取出商品的所有id,就可以这样写(伪代码): List productList = productService.selectAll(); List pIds = productList.stream().map(p->p.getId).collect(Collectors.toList()); 这样就可以拿到所有商品id的集合。
3、flatMap():扁平化映射,它具体的操作是将多个stream连接成一个stream,这个操作是针对类似多维数组的,比如集合里面包含集合,相当于降维作用。
flatMap是将流中的每个元素都放到一个流中,最后将所有的流合并成一个新流,所有流对象中的元素都合并到这个新生成的流中返回。
// flatMap:将多层集合中的元素取出来,放到一个新的集合中去
List<Integer> num1 = Arrays.asList(1, 2, 3);
List<Integer> num2 = Arrays.asList(4, 5, 6);
List<Integer> num3 = Arrays.asList(7, 8, 9);
List<List<Integer>> lists = Arrays.asList(num1, num2, num3);
Stream<Integer> outputStream = lists.stream().flatMap(l -> l.stream());
List<Integer> flatMapResult = outputStream.sorted().collect(Collectors.toList());
System.out.println(flatMapResult);
运行结果:
示例场景:取出所有部门人员的姓名,就可以这样写(伪代码): // 1、取出所有部门 List departments = …; // 2、这个时候可以利用flatMap先将所有部门的所有人员汇聚起来 List persons = departments.stream.flatMap(d->d.getPersonList()).collect(Collectors.toList()); // 3、再利用map()方法取出
4、distinct():顾名思义,将流中的元素去重之后输出。
List<String> mzc = Stream.of("L","e","o","shi","shuo","ma")
.distinct()
.collect(Collectors.toList());
System.out.println(mzc);
运行结果:
5、sorted():这个很简单了,顾名思义,将流中的元素按照自然排序方式进行排序。
// sorted:自然顺序排序
List<Integer> nums = Arrays.asList(1, 3, 5, 6, 8, 2);
List<Integer> sortedNum = nums.stream().sorted().collect(Collectors.toList());
System.out.println(sortedNum);
// sorted:降序排序
List<Integer> sortedNum2 = nums.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
System.out.println(sortedNum2);
// sorted:使用Comparator
List<Integer> sortedNums3 = nums.stream().sorted(Comparator.comparing(n -> n)).collect(Collectors.toList());
System.out.println(sortedNums3);
// 不用stream直接顺序排序
nums.sort(Comparator.comparing(Integer::intValue));
System.out.println(nums);
//不用stream直接降序排序
nums.sort(Comparator.comparing(Integer::intValue).reversed());
System.out.println(nums);
运行结果:
6、peek():对流中每个元素执行操作,并返回一个新的流,返回的流还是包含原来流中的元素。
// peek():
String[] arr = new String[]{"a","b","c","d"};
Arrays.stream(arr)
.peek(System.out::println) //a,b,c,d
.count();
// peek()+filter()
Stream.of("L", "e", "o")
.filter(e -> e.length() > 2)
.peek(e -> System.out.println(e))
.collect(Collectors.toList());
运行结果:
7、limit():顾名思义,返回指定数量的元素的流。返回的是Stream里前面的n个元素。
// limit():取出100中的前十个
List<Integer> limitNum = IntStream.range(1,100).limit(10)
.boxed()
.collect(Collectors.toList());
System.out.println(limitNum);
// limit():取出前4个单词
List<String> words = Arrays.asList("ma", "zhi", "chu", "wait", "you", "follow");
List<String> limitWord = words.stream().limit(4).collect(Collectors.toList());
System.out.println(limitWord);
运行结果:
8、skip():和limit()相反,将前几个元素跳过(取出)再返回一个流,如果流中的元素小于或者等于n,就会返回一个空的流。
// skip():跳过前面三个单词再返回
List<String> words = Arrays.asList("mg", "chi", "cldfkju", "wait", "you", "follow");
List<String> skipWord = words.stream().limit(4).collect(Collectors.toList());
System.out.println(skipWord);
// skip():跳过全部单词再返回
List<String> emptyWord = words.stream().skip(6).collect(Collectors.toList());
System.out.println(emptyWord);
// skip():跳过超过单词长度的数目再返回
List<String> emptyWord2 = words.stream().skip(10).collect(Collectors.toList());
System.out.println(emptyWord);
运行结果:
Stream流的终端操作主要有以下几种,我们来一一讲解。
终端操作代码实例详解
1、forEach():遍历流中的每一个元素,按照指定的方法执行,执行顺序不一定按照流的顺序。
// foreach:遍历流中每一个元素,执行顺序按照流的顺序
Stream.of(1,2,3,4,5,6).forEach(System.out::println);
// foreach:遍历流中每一个元素,执行顺序不一定按照流的顺序,.parallel()表示创建一个并行流
Stream.of(1,2,3,4,5,6).parallel().forEach(System.out::println);
运行结果:
2、forEachOrdered():遍历流中的每一个元素,按照指定的方法执行,执行顺序按照流的顺序。
// forEachOrdered():遍历流中每一个元素,执行顺序按照流的顺序
Stream.of(1,2,3,4,5,6).forEachOrdered(System.out::println);
// forEachOrdered:遍历流中每一个元素,执行顺序按照流的顺序,.parallel()表示创建一个并行流
Stream.of(1,2,3,4,5,6).parallel().forEachOrdered(System.out::println);
运行结果:
3、toArray():将流中的元素放入到一个数组中
// toArray():将流中的元素放入到一个数组中
String[] strings = Stream.of("ma", "zhi", "chu").toArray(String[]::new);
System.out.println(Arrays.toString(strings));
运行结果:
4、reduce():这个方法的主要作用是把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce。
// reduce():字符串拼接
String reduceStr1 = Stream.of("ma", "zhi", "chu").reduce("", String::concat);
String reduceStr2 = Stream.of("ma", "zhi", "chu").reduce("", (x,y)->x+y);
System.out.println(reduceStr1);
System.out.println(reduceStr2);
// reduce():求和,identity(起始值)为0
Integer total1 = Stream.of(1,2,3,4).reduce(0, Integer::sum);
Integer total2 = Stream.of(1,2,3,4).reduce(0, (x, y) -> x +y);
System.out.println(total1);
System.out.println(total2);
// 求和,sumValue = 10, 无起始值
Integer total3 = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
System.out.println(total3);
// reduce():求最小值
double minValue = Stream.of(-1.1, 8.8, -2.2, -6.6).reduce(Double.MAX_VALUE, Double::min);
System.out.println(minValue);
运行结果:
5、collect():是Stream的一个函数,负责收集流。前面我们说中间操作是将一个流转换成另一个流,这些操作是不消耗流的,但是终端操作会消耗流,产生一个最终结果,collect()就是一个规约操作,将流中的结果汇总。结果是由传入collect()中的Collector定义的。
// collect():负责收集流,将结果汇总,比如将下面的流中的结果汇总到一个集合中去
List<Integer> skipNum = IntStream.range(1,100).skip(90)
.boxed()
.collect(Collectors.toList());
System.out.println(skipNum);
运行结果:
6、min():返回流中的最小值
// min():返回流中的最小值
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
Integer minNum = nums.stream().min(Integer::compareTo).get();
Integer min = nums.stream().min((x,y) -> x.compareTo(y)).get();
System.out.println(minNum);
System.out.println(min);
运行结果:
7、max():返回流中的最大值
// max():返回流中的最大值
List<Integer> num = Arrays.asList(1, 2, 3, 4, 5, 6);
Integer maxNum = num.stream().max(Integer::compareTo).get();
Integer max = num.stream().max(Comparator.comparing(Function.identity())).get();
System.out.println(maxNum);
System.out.println(max);
运行结果:
8、count():返回流中元素的数量
// count():返回流中元素的数量
List<Integer> ls = Arrays.asList(1,2,3,4,5);
long count = ls.stream().count();
long count1 = ls.stream().filter(l -> l > 2).count();
System.out.println(count);
System.out.println(count1);
运行结果:
9、anyMatch():Stream 中只要有一个元素符合传入的断言,就返回 true,否则返回false。
// anyMatch():判断流中数据是否有一个复合断言
List<Integer> ins = Arrays.asList(1,2,3,4,5);
boolean b = ins.stream().anyMatch(l -> l > 2);
boolean b1 = ins.stream().anyMatch(l -> l > 5);
System.out.println(b);
System.out.println(b1);
// anyMatch():判断流中数据是否有一个复合断言,如果流为空,永远返回false
List<Integer> inss = Arrays.asList();
boolean b2 = inss.stream().anyMatch(l -> l > 2);
System.out.println(b2);
运行结果:
10、allMatch():Stream 中所有元素都符合传入的断言时返回 true,否则返回false,流为空时总是返回true。
// allMatch():判断流中元素是否都符合断言条件
List<Integer> ints = Arrays.asList(1,2,3,4,5);
boolean c = ints.stream().allMatch(l -> l > 0);
boolean c1 = ints.stream().allMatch(l -> l > 1);
System.out.println(c);
System.out.println(c1);
// allMatch():判断流中元素是否都符合断言条件,如果流为空,永远返回true
List<Integer> emptyList = new ArrayList<>();
boolean c2 = emptyList.stream().allMatch(e -> e > 1);
System.out.println(c2);
运行结果:
11、noneMatch():Stream 中所有元素都不满足传入的断言时返回 true,否则返回false。
// noneMatch():判断流中元素是否都不符合传入的断言条件
List<Integer> numList = Arrays.asList(1,2,3,4,5);
boolean d = numList.stream().noneMatch(l -> l > 6);
boolean d1 = numList.stream().noneMatch(l -> l > 1);
System.out.println(d);
System.out.println(d1);
// noneMatch():判断流中元素是否都不符合传入的断言条件,流为空时永远返回true
List<Integer> numist = Arrays.asList();
boolean d2 = numist.stream().noneMatch(l -> l > 6);
System.out.println(d2);
运行结果:
12、findFirst():总是返回流中的第一个元素,如果流为空,返回一个空的Optional.
// findFirst():返回流中的第一个元素
List<Integer> integers = Arrays.asList(1, 2, 3);
Optional<Integer> first = integers.stream().findFirst();
System.out.println(first);
System.out.println(first.isPresent()); // 判断是否不等于null,isPresent()相当于!=null的判断
System.out.println(first.get());
//findFirst():返回流中的第一个元素,如果流为空,返回一个空的Optional
List<Integer> lls = Collections.EMPTY_LIST;
Optional<Integer> first1 = lls.stream().findFirst();
System.out.println(first1);
System.out.println(first1.isPresent());
运行结果:
13、findAny():返回流中的任意一个元素即可,如果流为空,返回一个空的Optional.
// findAny():返回流中任意一个元素,
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
Optional<Integer> any = list.stream().findAny();
// 并行流下每次返回的结果会不同
// Optional<Integer> any = list.stream().parallel().findAny();
System.out.println(any);
System.out.println(any.isPresent());
System.out.println(any.get());
// findAny():返回流中任意一个元素,如果流为空,返回一个空的Optional
List<Integer> list1 = Arrays.asList();
Optional<Integer> any1 = list1.stream().findAny();
System.out.println(any1);
System.out.println(any1.isPresent());
运行结果:
一个数据源(如:集合、数组),获取一个Stream流
在流的传输过程中,对Stream流进行处理
comparable:自然排序
终端操作:终止操作返回的是一个结果,就是所有中间操作做完之后进行的操作,比如汇总、遍历输出、求和等等
下图展示了Stream
的执行流程:
并行流是 Java 8 Stream API 中的一个特性。它可以将一个流的操作在多个线程上并行执行,以提高处理大量数据时的性能。
在传统的顺序流中,所有的操作都是在单个线程上按照顺序执行的。而并行流则会将流的元素分成多个小块,并在多个线程上并行处理这些小块,最后将结果合并起来。这样可以充分利用多核处理器的优势,加快数据处理的速度。
要将一个顺序流转换为并行流,只需调用流的 parallel() 方法即可。示例代码如下所示:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream()
.parallel()
.forEach(System.out::println);
在这个示例中,我们创建了一个包含整数的 List,并通过 stream() 方法将其转换为流。接着调用 parallel() 方法将流转换为并行流,然后使用 forEach 方法遍历流中的元素并输出。
需要注意的是,并行流的使用并不总是适合所有情况。并行流的优势主要体现在数据量较大、处理时间较长的场景下。对于小规模数据和简单的操作,顺序流可能更加高效。在选择使用并行流时,需要根据具体情况进行评估和测试,以确保获得最佳的性能。
此外,还需要注意并行流在某些情况下可能引入线程安全的问题。如果多个线程同时访问共享的可变状态,可能会导致数据竞争和不确定的结果。因此,在处理并行流时,应当避免共享可变状态,或采用适当的同步措施来确保线程安全。
使用并行流可以通过利用多线程并行处理数据,从而提高程序的执行性能。下面是一些使用并行流提高性能的常见方法:
创建并行流:要创建一个并行流,只需在普通流上调用 parallel()
方法。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> parallelStream = numbers.parallelStream();
利用任务并行性:并行流会将数据分成多个小块,并在多个线程上并行处理这些小块。这样可以充分利用多核处理器的优势。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.parallelStream()
.map(n -> compute(n)) // 在多个线程上并行处理计算
.forEach(System.out::println);
在这个示例中,使用 map
方法对流中的每个元素进行计算。由于并行流的特性,计算操作会在多个线程上并行执行,提高了计算的效率。
避免共享可变状态:在并行流中,多个线程会同时操作数据。如果共享可变状态(如全局变量)可能导致数据竞争和不确定的结果。因此,避免在并行流中使用共享可变状态,或者采取适当的同步措施来确保线程安全。
使用合适的操作:一些操作在并行流中的性能表现更好,而另一些操作则可能导致性能下降。一般来说,在并行流中使用基于聚合的操作(如 reduce
、collect
)和无状态转换操作(如 map
、filter
)的性能较好,而有状态转换操作(如 sorted
)可能会导致性能下降。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// good performance
int sum = numbers.parallelStream()
.reduce(0, Integer::sum);
// good performance
List<Integer> evenNumbers = numbers.parallelStream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
// potential performance degradation
List<Integer> sortedNumbers = numbers.parallelStream()
.sorted()
.collect(Collectors.toList());
在这个示例中,reduce
和 filter
的操作在并行流中具有良好的性能,而 sorted
操作可能导致性能下降。
除了上述方法,还应根据具体情况进行评估和测试,并行流是否能够提高性能。有时候,并行流的开销(如线程的创建和销毁、数据切割和合并等)可能超过了其带来的性能提升。因此,在选择使用并行流时,应该根据数据量和操作复杂度等因素进行综合考虑,以确保获得最佳的性能提升。
map
、filter
)时表现较好。这类操作不依赖于其他元素的状态,每个元素的处理是相互独立的,可以很容易地进行并行处理。
并行流的注意事项包括:
sorted
)可能导致性能下降或结果出现错误。在使用并行流时,应注意避免这类操作,或者在需要时采取适当的处理措施。
以上便是本文的全部内容,本人才疏学浅,文章有什么错误的地方,欢迎大佬们批评指正!我是Leo,一个在互联网行业的小白,立志成为更好的自己。
如果你想了解更多关于Leo,可以关注公众号-程序员Leo,后面文章会首先同步至公众号。