本文重点介绍Java 8中新增的类库特性,包括Streams API、Collectors以及并行处理机制。
1. Streams API简介
Java 8引入了流(Stream)的概念,用于对集合进行高级操作。Stream并不存储数据,而是表示一种可以执行操作的数据序列。以下代码展示了如何使用Stream将集合中的形状颜色设置为红色:
shapes.stream()
.filter(s -> s.getColor() == BLUE)
.forEach(s -> s.setColor(RED));
这里,`filter`方法用于筛选蓝色形状,而`forEach`则负责修改它们的颜色。
2. Collectors的使用
Collectors提供了多种方式来汇总或收集流中的元素。例如,将筛选后的元素收集到列表中:
List<Shape> blueShapes = shapes.stream()
.filter(s -> s.getColor() == BLUE)
.collect(Collectors.toList());
如果需要将结果映射到特定结构,如`Set`:
Set<Box> boxesWithBlueShapes = shapes.stream()
.filter(s -> s.getColor() == BLUE)
.map(Shape::getBox)
.collect(Collectors.toSet());
3. 并行处理
通过`parallelStream()`,可以轻松实现并行处理。例如,计算蓝色形状的总重量:
int totalWeight = shapes.parallelStream()
.filter(s -> s.getColor() == BLUE)
.mapToInt(Shape::getWeight)
.sum();
需要注意的是,并行处理要求操作无副作用且不干扰数据源。
4. 惰性求值
Stream的操作大多是惰性求值的,这意味着只有在终端操作触发时才会实际执行中间操作。例如:
int sum = shapes.stream()
.filter(s -> s.getColor() == BLUE)
.mapToInt(Shape::getWeight)
.sum();
上述代码中,`filter`和`mapToInt`不会立即执行,直到`sum`被调用。
5. 示例:复杂查询
假设我们有一个音乐库,包含专辑和音轨信息。要获取所有含有四星及以上音轨的专辑,并按名称排序:
List<Album> favoriteAlbums = albums.stream()
.filter(a -> a.getTracks().stream()
.anyMatch(t -> t.getRating() >= 4))
.sorted(Comparator.comparing(Album::getName))
.collect(Collectors.toList());
6. 自定义收集器
除了内置的Collectors,还可以创建自定义收集器。例如,生成一个基于艺术家分组的歌曲集:
Map<Artist, Set<Track>> tracksByArtist = tracks.stream()
.filter(t -> t.getRating() >= 4)
.collect(Collectors.groupingBy(
Track::getArtist,
Collectors.toSet()));
7. Spliterator与并行机制
`Spliterator`是Stream并行处理的核心组件,它允许将数据分解为多个部分以便并发处理。以下是其接口定义:
public interface Spliterator<T> {
boolean tryAdvance(Consumer<? super T> action);
Spliterator<T> trySplit();
long estimateSize();
int characteristics();
}
通过递归分解,`Spliterator`能够高效地支持并行操作。