使用Java 8对整数列表求和
我只是在玩Java8,并使用一个程序来计算一个大列表中偶数的总和,将一些东西与Java6进行比较 Java8使用Java 8对整数列表求和,java,biginteger,java-8,Java,Biginteger,Java 8,我只是在玩Java8,并使用一个程序来计算一个大列表中偶数的总和,将一些东西与Java6进行比较 Java8 public class ListOperationsJava8 { static List<BigInteger> list = new LinkedList<>(); public static void main(String[] args) { createList(); long start = Sy
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)));
}
}
}
对于第一个问题:您的值可能大于
Integer.MAX\u value
,因此溢出,这意味着它将在外部表示为从Integer.MIN\u value
开始溢出是此处的关键字
对于第二部分,我不知道它到底为什么不同,可能最终可以在字节码中找到,但这真的是一个问题,还是一个过早优化的案例?如果是第一种情况,那么你应该担心,如果是第二种情况,那么你不应该注意它变慢了
但我从您的代码中观察到的一个区别是:
- Java 6:使用一个
,并对其调用biginger sum
方法.add()
- Java8:使用一些
变量,并在内部将该变量添加到long
parallelStream()
来进行非常快速的计算,这可能会导致一个问题,即创建新的底层线程实际上比使用普通的线性stream()
要花费更多的时间
此外,如果您真的在测量速度,那么您应该做更多的测试,而不是每个测试用例运行一次,时间也可能取决于其他因素——JVM、CPU的时钟速度等等
最后一次编辑时,您的Java 8代码实际上并不代表您的Java 6代码,它应该是:
final BigInteger sum = BigInteger.ZERO;
list.stream()
.filter(n -> n.mod(new BigInteger("2")).equals(BigInteger.ZERO))
.forEach(n -> { sum = sum.add(n); });
要想完整地表示您的Java 6代码,请注意,sum
的引入在这里并不是一件好事,如果您将它用于并行计算,那么这段代码根本不起作用
最后一次编辑是为了正确显示在Java 8中应该如何操作,它看起来是正确的,适用于并行版本,甚至可能在线性版本中获得额外的性能:
Optional<BigInteger> sum = list.stream()
.filter(n -> n.mod(new BigInteger("2")).equals(BigInteger.ZERO))
.reduce((n1, n2) -> n1.add(n2));
System.out.println(sum.get());
Optional sum=list.stream()
.filter(n->n.mod(新的BigInteger(“2”)).equals(BigInteger.ZERO))
.减少((n1,n2)->n1.添加(n2));
System.out.println(sum.get());
这里我使用reduce()
运算符,它将BinaryOperator
作为参数,我使用它将BigInteger
添加到一起
需要注意的一点是,流可能是空的,因此它不知道是否有值,因此它返回一个可选的
请仔细注意,通常您需要调用sum.isPresent()
来检查它是否实际有值,但在这里我们知道必须有一个值作为!list.isEmpty()
,因此我们直接调用sum.get()
最后,我在我的电脑上测试了100万个数字的不同版本:
- Java6:大约190~210ms
- Java8您的代码:大约160~220ms
- Java 8,矿井线性:大约180~260ms
- Java 8,水雷并行:大约180~270ms
因此,由于这并不是真正正确的微基准测试,我认为结论是,你在这种情况下使用什么并不重要。这是我的快速而肮脏的基准测试,允许在每次测试之间进行JIT预热和GC校准。结果是:
2499950000
Time taken using Java 6: 52 ms
2499950000
Time taken using Java 8: 249 ms
- 循环频率:686毫秒
- lamdbda:681毫秒
- 平行λ:405毫秒
我还删除了在每次迭代中不必要地创建新的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);
}
}
公共类Test1{
静态列表=新建LinkedList();
静态BigInteger二=新的BigInteger(“2”);
公共静态void main(字符串[]args){
createList();
长和=0;
//热身
对于(int i=0;i<100;i++){
sum+=forLoop().longValue();
sum+=lambda().longValue();
sum+=parallelLambda().longValue();
}
{
gc();
长启动=System.currentTimeMillis();
对于(int i=0;i<100;i++)sum+=forLoop().longValue();
long end=System.currentTimeMillis();
println(“使用for循环所花费的时间:”+(结束-开始)+“毫秒”);
}
{
gc();
长启动=System.currentTimeMillis();
对于(int i=0;i<100;i++)sum+=lambda().longValue();
long end=System.currentTimeMillis();
System.out.println(“使用lambda所花费的时间:”+(结束-开始)+“毫秒”);
}
{
gc();
长启动=System.currentTimeMillis();
对于(int i=0;i<100;i++)和+=parallelLambda().longValue();
long end=System.currentTimeMillis();
System.out.println(“使用parallelLambda所花费的时间:”+(结束-开始)+“毫秒”);
}
}
私有静态void createList(){
对于(int i=0;i<100000;i++){
添加(新的biginger(String.valueOf(i));
}
}
私有静态BigInteger forLoop(){
BigInteger总和=BigInteger.0;
for(biginger n:list){
if(n.mod(2).equals(BigInteger.ZERO))
总和=总和。加(n);
}
回报金额;
}
私有静态BigInteger lambda(){
返回list.stream()。
过滤器(n->n.mod(两个).equals(零))。
reduce(零,BigInteger::add);
}
私有静态BigInteger并行lambda(){
返回list.parallelStream()。
过滤器(n->n.mod(两个).equals(零))。
reduce(零,BigInteger::add);
}
}
您只需
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);
}
}
list.parallelStream()
.filter(n -> n.mod(new BigInteger("2")).equals(BigInteger.ZERO))
.reduce(BigDecimal.ZERO, BigDecimal::add)