收集器

一种通用的、从流生成复杂值的结构,只要把它传给collect方法,所有的流就都可以使用它了。

标准类库已经提供了一些有用的收集器,下面示例代码中的收集器都是从java.util.stream.Collectors类中导入的。

转换成其他集合

使用Collectors.toList,还有toSet、toCollection等,这里不需要指定具体的类型,Stream类库在背后自动挑选合适的类型。

如果需要指定具体的类型,可以使用toCollection,用定制的集合收集元素

// 使用TreeSet收集元素
Stream.of(1, 2, 3).collect(Collectors.toCollection(TreeSet::new));

转换成值

可以利用收集器让流生成一个值

// 计算每个元素加1后的平均值
Stream.of(1, 2, 3).collect(Collectors.averagingInt(number -> number + 1));

数据分块

另外一种常用的流操作是将其分解为两个集合。可以使用收集器partitioningBy,它接收一个流,并将其分成两部分(使用Predicate对象判断一个元素应该属于哪个部分,并根据布尔值返回一个map到列表)

// 分别找出奇数和偶数
Map<Boolean, List<Integer>> collect = 
                Stream.of(1, 2, 3, 4).collect(Collectors.partitioningBy(number -> number % 2 == 0));

数据分组

数据分组是一种更自然的分割数据操作,与将数据分成true和false不同,可以使用任意值对数据分组。使用groupingBy可以对流进行分组

List<Track> tracks = Arrays.asList(new Track("Bakal", 524),
                new Track("Violets for Your Furs", 378),
                new Track("Bakal", 451));

// 根据名称来分组
Map<String, List<Track>> collect = 
                tracks.stream().collect(Collectors.groupingBy(track -> track.getName()));

// 使用方法应用优化
Map<String, List<Track>> collect = 
                tracks.stream().collect(Collectors.groupingBy(Track::getName));

字符串

很多时候,收集流中的数据都是为了在最后生成一个字符串。可以使用joining

List<Track> tracks = Arrays.asList(new Track("Bakal", 524),
                new Track("Violets for Your Furs", 378),
                new Track("Bakal", 451));

// 使用map提取名称,使用joining得到一个字符串,允许用户指定分割符、前缀、后缀
String collect = tracks.stream()
                .map(Track::getName)
                .collect(Collectors.joining(", ", "[", "]"));

组合收集器

可以使用第二个收集器,用以收集最终结果的一个子集,这些收集器叫做下游收集器。收集器是生成最终结果的一剂配方,下游收集器是生成部分结果的配方,主收集器中会用到下游收集器。

List<Track> tracks = Arrays.asList(new Track("Bakal", 524),
                new Track("Violets for Your Furs", 378),
                new Track("Bakal", 451));

// 计算每个分组下的数量
Map<String, Long> collect =
                tracks.stream()
                        .collect(Collectors.groupingBy(Track::getName, Collectors.counting()));

自定义收集器

除此之外,还可以自定义收集器,这里不再展开

练习

使用Map的computeIfAbsent方法高效计算斐波那契数列

public class Fibonacci {

    private static final Map<Integer,Long> cache;

    static {
        cache = new HashMap<>();
        cache.put(0, 0L);
        cache.put(1, 1L);
    }

    public static long fibonacci(int x) {
        // 当cache中有时,则直接计算,如果没有则计算并放入cache中
        return cache.computeIfAbsent(x, n -> fibonacci(n-1) + fibonacci(n-2));
    }

    public static void main(String[] args) {
        System.out.println(fibonacci(10));
        cache.forEach((key, value) -> {
            System.out.println(key + ": " + value);
        });
    }
}

猜你喜欢

转载自my.oschina.net/u/3198904/blog/1788650