如何获取系统中消费最高的10位Taxpayer?(非Java 8实现)
问题:获取消费总额最高的10位Taxpayer(非Java 8实现)
背景与需求
咱们先梳理下当前场景:
- 现有类结构:
User基类,Taxpayer继承自User,还有记录消费明细的Expense类 Main类维护两个核心集合:Map<String, User> users(存储系统所有用户)和Map<String, Expense> expenses(存储所有消费记录)- 核心需求:找出系统内消费总额最高的10位Taxpayer,需要先判断用户是否为Taxpayer身份,再计算其所有消费的金额总和
- 现存问题:当前代码完全没处理「列表已满10个时,替换掉消费额更低的末尾用户」的逻辑,而且要求必须用非Java 8的实现方式
现有问题代码
public List<Taxpayer> getTenTaxpayers(){ List<Taxpayer> list = new ArrayList<Taxpayer>(); for(User u: this.users.values()){ if(!u.getUserType()){ // 原代码逻辑:getUserType返回false代表是Taxpayer Taxpayer t = (Taxpayer) u; double sum = 0; for(Expense e: this.expenses.values()){ if(t.getNIF().equals(e.getNIFClient())){ // 通过NIF匹配Taxpayer和其消费记录 sum += e.getValue(); if(list.size()<10){ list.add(t.clone()); } } } } } return list; // 原代码遗漏return,这里补上 }
问题分析
这段代码有两个核心硬伤:
- 效率极低:每遍历一个Taxpayer,就要全量扫描所有Expense记录,重复计算量极大,时间复杂度是O(M*N)(M为用户数,N为消费记录数)
- 逻辑缺失:只处理了列表未满10个的场景,完全没考虑当列表已满时,如何替换掉消费额更低的末尾元素,也没有对列表按消费总额排序
非Java 8解决方案
我们分两步优化:先预处理消费总额减少重复计算,再维护一个有序的Top10列表
步骤1:预处理消费总额
先遍历所有Expense,按客户NIF统计总消费金额,存在一个Map中。后续每个Taxpayer直接从Map中取对应总额即可,不用反复扫描Expense集合。
步骤2:维护有序的Top10列表
保持列表始终按消费总额降序排列:
- 当列表未满10个时,直接加入新的Taxpayer并重新排序
- 当列表已满10个时,比较当前Taxpayer的总额与列表最后一位的总额,如果更高,就替换末尾元素并重新排序
修正后的代码
import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; public List<Taxpayer> getTenTaxpayers() { // 第一步:预处理所有消费记录,按NIF统计总消费金额 Map<String, Double> nifExpenseSumMap = new HashMap<String, Double>(); for (Expense e : this.expenses.values()) { String clientNif = e.getNIFClient(); // 累加当前NIF的消费总额,没有记录则默认0 double currentTotal = nifExpenseSumMap.getOrDefault(clientNif, 0.0); nifExpenseSumMap.put(clientNif, currentTotal + e.getValue()); } // 第二步:维护消费总额最高的10位Taxpayer列表 List<Taxpayer> top10Taxpayers = new ArrayList<Taxpayer>(); for (User u : this.users.values()) { // 按原代码逻辑判断是否为Taxpayer if (!u.getUserType()) { Taxpayer taxpayer = (Taxpayer) u; String nif = taxpayer.getNIF(); // 获取该Taxpayer的总消费,无消费则为0 double totalExpense = nifExpenseSumMap.getOrDefault(nif, 0.0); if (top10Taxpayers.size() < 10) { // 列表未满10个,直接加入克隆后的对象(避免修改原数据) top10Taxpayers.add(taxpayer.clone()); // 排序:按消费总额降序排列 Collections.sort(top10Taxpayers, new Comparator<Taxpayer>() { @Override public int compare(Taxpayer t1, Taxpayer t2) { double sum1 = nifExpenseSumMap.getOrDefault(t1.getNIF(), 0.0); double sum2 = nifExpenseSumMap.getOrDefault(t2.getNIF(), 0.0); // 降序排列,用Double.compare避免精度问题 return Double.compare(sum2, sum1); } }); } else { // 列表已满,取当前列表末尾(消费最低)的Taxpayer总额 Taxpayer lowestTopTaxpayer = top10Taxpayers.get(top10Taxpayers.size() - 1); double lowestTotal = nifExpenseSumMap.getOrDefault(lowestTopTaxpayer.getNIF(), 0.0); // 如果当前Taxpayer消费更高,替换末尾元素并重新排序 if (totalExpense > lowestTotal) { top10Taxpayers.remove(top10Taxpayers.size() - 1); top10Taxpayers.add(taxpayer.clone()); Collections.sort(top10Taxpayers, new Comparator<Taxpayer>() { @Override public int compare(Taxpayer t1, Taxpayer t2) { double sum1 = nifExpenseSumMap.getOrDefault(t1.getNIF(), 0.0); double sum2 = nifExpenseSumMap.getOrDefault(t2.getNIF(), 0.0); return Double.compare(sum2, sum1); } }); } } } } return top10Taxpayers; }
关键优化点说明
- 效率提升:时间复杂度从O(M*N)降到O(M+N),大幅减少重复计算
- 逻辑完善:实现了「满10个时替换低消费用户」的核心逻辑,且始终保持列表有序
- 非Java 8兼容:完全使用Java 7及之前的API,没有用到Stream、Lambda等Java 8特性
- 数据安全:保留原代码的
t.clone()操作,避免修改原User对象的引用
内容的提问来源于stack exchange,提问作者John Mulaney
相关产品推荐
相关产品推荐

