java 8 第15篇 给定数字,输出先前的所有的质素和非质素(优化)

本文介绍了一种使用自定义收集器优化质数筛选的方法,通过并行处理和流API,有效地对整数流进行分区,区分质数与非质数。此收集器实现了Collector接口,利用并行收集的优势,提高了大规模数据处理的效率。

**
 * 获取质素和非质素的优化;
 * 其中T、A和R分别是流中元素的类型、用于累积部分结果的对象类型,以及collect操作最
 * 终结果的类型。这里应该收集Integer流,而累加器和结果类型则都是Map<Boolean,
 * List<Integer>>
 */
public class PrimeNumbersCollector implements Collector<Integer,
        Map<Boolean, List<Integer>>,
        Map<Boolean, List<Integer>>> {
    /**
     * supplier方法会返回一个在调用时创建累加器的函数。
     * 这里不但创建了用作累加器的Map,还为true和false两个键下面初始化了对应的空列表。
     * 在收集过程中会把质数和非质数分别添加到这里。
     * @return
     */
    @Override
    public Supplier<Map<Boolean, List<Integer>>> supplier() {
        return () -> new HashMap<Boolean, List<Integer>>() {{
            put(true, new ArrayList<Integer>());
            put(false, new ArrayList<Integer>());
        }};
    }

    /**
     * 收集器中最重要的方法是accumulator,因
     * 为它定义了如何收集流中元素的逻辑。这里它也是实现前面所讲的优化的关键。现在在任何一次
     * 迭代中,都可以访问收集过程的部分结果,也就是包含迄今找到的质数的累加器.在这个方法中,你调用了isPrime方法,将待测试是否为质数的数以及迄今找到的质数列表
     * (也就是累积Map中true键对应的值)传递给它。这次调用的结果随后被用作获取质数或非质数
     * 列表的键,这样就可以把新的被测数添加到恰当的列表中
     * @return
     */
    @Override
    public BiConsumer<Map<Boolean, List<Integer>>, Integer> accumulator() {
        return (Map<Boolean, List<Integer>> acc, Integer candidate) -> {
            acc.get(isPrime(acc.get(true),
                    candidate))
                    .add(candidate);
        };
    }

    /**
     * 要在并行收集时把两个部分累加器合并起来,这里,它只需要合并两个Map,即
     * 将第二个Map中质数和非质数列表中的所有数字合并到第一个Map的对应列表中就行了
     * @return
     */
    @Override
    public BinaryOperator<Map<Boolean, List<Integer>>> combiner() {
        return (Map<Boolean, List<Integer>> map1,
                Map<Boolean, List<Integer>> map2) -> {
            map1.get(true).addAll(map2.get(true));
            map1.get(false).addAll(map2.get(false));
            return map1;
        };
    }

    /**
     * 最后两个方法的实现都很简单。前面说过,accumulator正好就是收集器的结果,用不着
     * 进一步转换,那么finisher方法就返回identity函数
     * @return
     */
    @Override
    public Function<Map<Boolean, List<Integer>>,
            Map<Boolean, List<Integer>>> finisher() {
        return Function.identity();
    }

    @Override
    public Set<Characteristics> characteristics() {
        return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH));
    }

    public static boolean isPrime(List<Integer> primes, int candidate) {
        int candidateRoot = (int) Math.sqrt((double) candidate);
        return takeWhile(primes, i -> i <= candidateRoot)
                .stream()
                .noneMatch(p -> candidate % p == 0);
    }

    public static <A> List<A> takeWhile(List<A> list, Predicate<A> p) {
        int i = 0;
        for (A item : list) {
            if (!p.test(item)) {
                return list.subList(0, i);
            }
            i++;
        }
        return list;
    }

    public static void main(String[] args) {
        Map<Boolean, List<Integer>> map = new PrimeNumbersCollector().partitionPrimesWithCustomCollector(20);
        System.out.println(map.toString());
    }

    public Map<Boolean, List<Integer>>
    partitionPrimesWithCustomCollector(int n) {
        return IntStream.rangeClosed(2, n).boxed()
                .collect(new PrimeNumbersCollector());
    }
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值