java - 使用 Java 8 的整数列表的总和

标签 java biginteger java-8

我只是在玩弄 Java 8,并使用程序计算大型列表中偶数的总和,将一些事情与 Java 6 进行了比较

Java 8

public class ListOperationsJava8 {

    static List<BigInteger> list = new LinkedList<>();

    public static void main(String[] args) {
        createList();

        long start = System.currentTimeMillis();

        /*System.out.println(list.parallelStream().
                filter(n -> n.mod(new BigInteger("2")).equals(BigInteger.ZERO)).
                        mapToInt(BigInteger::intValue).sum());  --> gives result        -1795017296 */

        System.out.println(list.parallelStream().
                filter(n -> n.mod(new BigInteger("2")).equals(BigInteger.ZERO)).
                    mapToLong(BigInteger::longValue).sum());

        long end = System.currentTimeMillis();

        System.out.println("Time taken using Java 8:  " + (end - start) + " ms");
    }

    private static void createList() {
        for (int i = 0; i < 100000; i++) {
            list.add(new BigInteger(String.valueOf(i)));
        }
    }
}

Java 6

public class ListOperationsClassic {

    static List<BigInteger> list = new LinkedList<BigInteger>();

    public static void main(String[] args) {
        createList();

        long start = System.currentTimeMillis();

        BigInteger sum = BigInteger.ZERO;

        for(BigInteger n : list) {
            if(n.mod(new BigInteger("2")).equals(BigInteger.ZERO))
                sum = sum.add(n);
        }

        System.out.println(sum);

        long end = System.currentTimeMillis();

        System.out.println("Time taken using Java 6: " + (end - start) + " ms");
    }

    private static void createList() {
        for (int i = 0; i < 100000; i++) {
            list.add(new BigInteger(String.valueOf(i)));
        }
    }
}

我有两个问题

  1. 在 Java 8 代码中,最初我使用 mapToInt(BigInteger::intValue).sum()) 减少值,但是 得到了否定结果 -1795017296!为什么?预期结果 2499950000 本身在一个 int 可以表示的范围内,因为我 明白。
  2. 我多次运行代码,总能找到 Java 8 中的代码 花费的时间比使用 Java 6 的代码多 5 倍。那是什么 可能是什么意思对于这种规模的操作,不值得使用 parallelStream 和/或 reduce 操作和普通的旧 for 循环 更好吗?

这是其中一个结果:

2499950000
Time taken using Java 6: 52 ms

2499950000
Time taken using Java 8:  249 ms

最佳答案

这是我的快速基准测试,允许在每次测试之间进行 JIT 预热和 GC。结果:

  • for 循环:686 毫秒
  • lamdbda:681 毫秒
  • 并行 lambda:405 毫秒

请注意,我已经修改了您的代码,使三个测试尽可能等效 - 特别是对于 lambda,我使用归约来添加 BigIntegers 而不是转换为 long。
我还删除了每次迭代时不必要的 new BigInteger("2") 创建。

public class Test1 {

    static List<BigInteger> list = new LinkedList<>();
    static BigInteger TWO = new BigInteger("2");

    public static void main(String[] args) {
        createList();

        long sum = 0;

        //warm-up
        for (int i = 0; i < 100; i++) {
            sum += forLoop().longValue();
            sum += lambda().longValue();
            sum += parallelLambda().longValue();
        }

        {
            System.gc();
            long start = System.currentTimeMillis();
            for (int i = 0; i < 100; i++) sum += forLoop().longValue();
            long end = System.currentTimeMillis();
            System.out.println("Time taken using for loop:  " + (end - start) + " ms");
        }

        {
            System.gc();
            long start = System.currentTimeMillis();
            for (int i = 0; i < 100; i++) sum += lambda().longValue();
            long end = System.currentTimeMillis();
            System.out.println("Time taken using lambda:  " + (end - start) + " ms");
        }

        {
            System.gc();
            long start = System.currentTimeMillis();
            for (int i = 0; i < 100; i++) sum += parallelLambda().longValue();
            long end = System.currentTimeMillis();
            System.out.println("Time taken using parallelLambda:  " + (end - start) + " ms");
        }
    }

    private static void createList() {
        for (int i = 0; i < 100000; i++) {
            list.add(new BigInteger(String.valueOf(i)));
        }
    }

    private static BigInteger forLoop() {
        BigInteger sum = BigInteger.ZERO;

        for(BigInteger n : list) {
            if(n.mod(TWO).equals(BigInteger.ZERO))
                sum = sum.add(n);
        }
        return sum;
    }

    private static BigInteger lambda() {
        return list.stream().
                filter(n -> n.mod(TWO).equals(ZERO)).
                reduce(ZERO, BigInteger::add);
    }

    private static BigInteger parallelLambda() {
        return list.parallelStream().
                filter(n -> n.mod(TWO).equals(ZERO)).
                reduce(ZERO, BigInteger::add);
    }
}

关于java - 使用 Java 8 的整数列表的总和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21940693/

相关文章:

java - 在Java中,为什么map.get(key)[0]作为左侧有效,而map.get(key)则无效?

java - 为什么大型 RSA key 不加密为唯一值?

格式化长数字时,PHP 给出不正确的结果

Java 8 句子流

java - -> <- 运算符是做什么的?

java - JFrame/JPanel 刷新和文本字段

java - 尝试使用复杂公式时出现 "Cannot find symbol"错误

java - 如何使用 codehaus 包类从 POJO 生成 JSON 架构时添加描述属性

biginteger - 是否有一种节省空间的方法来计算高指数的 gcd?

Java 8 嵌套流 - 转换链式 for 循环