Java8 Stream计算四数最小最大和结果异常问题排查
问题描述
给定5个正整数,计算选取恰好4个整数求和可得到的最小值、最大值,最终将两个long类型的计算结果以空格分隔为单行输出。
异常表现
- 小数值测试用例运行正常:输入
[1, 2, 3, 4, 5]时,输出最小值10、最大值14,结果符合预期 - 大数值测试用例运行失败:输入
[256741038, 623958417, 467905213, 714532089, 938071625]时,代码输出最小值2063136757、最大值-1550499952,预期正确结果为最小值2063136757、最大值2744467344 - 初步定位:问题大概率出现在
long max的赋值语句处,尤其是.sorted(Collections.reverseOrder())逻辑,这是最小和、最大和计算语句之间唯一的实质差异
原实现代码
class Result { /* * Complete the 'miniMaxSum' function below. * * The function accepts. INTEGER_ARRAY arr as parameter. */ public static void miniMaxSum(List<Integer> arr) { long max = arr.stream().sorted(Collections.reverseOrder()) .limit(4) .reduce(0, (subtotal, element) -> subtotal + element); long min = arr.stream().sorted().limit(4).reduce(0, (subtotal, element) -> subtotal + element); System.out.println(min + " " + max); } } public class Solution { public static void main(String[] args) throws IOException { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); List<Integer> arr = Stream .of(bufferedReader.readLine().replaceAll("\\s+$", "") .split(" ")) .map(Integer::parseInt).collect(toList()); Result.miniMaxSum(arr); bufferedReader.close(); } }
问题根因
问题和倒序排序逻辑无关,核心是
reduce操作的初始值0为int类型,导致整个累加过程按int类型运算,触发整数溢出:
- Java中int类型的最大值为
2^31-1 = 2147483647,一旦累加和超过这个值就会溢出为负数- 计算最小和时,取正序排列的前4个最小数相加,和为2063136757,小于int最大值,未触发溢出,因此结果正确
- 计算最大和时,取倒序排列的前4个最大数相加,和为2744467344,远大于int最大值,累加过程中int溢出得到负数结果,即便最终赋值给long类型,保存的也已经是溢出后的错误值
修复方案
将reduce的初始值从int类型的0改为long类型的0L,让整个累加过程按long类型运算,从根源避免整数溢出。修复后的核心代码如下:
public static void miniMaxSum(List<Integer> arr) { long max = arr.stream().sorted(Collections.reverseOrder()) .limit(4) .reduce(0L, (subtotal, element) -> subtotal + element); long min = arr.stream().sorted().limit(4).reduce(0L, (subtotal, element) -> subtotal + element); System.out.println(min + " " + max); }
内容的提问来源于stack exchange,提问作者Nasri
相关产品推荐
相关产品推荐

