Java中如何按两个BigDecimal的差值对Quotation列表排序?
按Spread排序Quotation列表的正确实现
原代码的问题分析
- 比较逻辑完全错误:原代码中
a.getBidPrice().intValue() - b.getAskPrice().intValue()并非比较两个Quotation对象的Spread,而是跨对象取bid和ask值相减,完全不符合需求。 - 直接修改原始列表:
sortedBySpread = QuotationsStoreImpl.quotationList会直接操作原始数据集合,可能导致其他依赖原始列表的功能出错,应该创建副本再排序。 - BigDecimal转int丢失精度:如果价格包含小数(如
100.5),intValue()会截断小数部分,导致Spread计算错误,必须使用BigDecimal自身的方法进行运算和比较。
正确实现代码
import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class QuotationsStoreImpl { // 存储Quotation的原始列表 public static List<Quotation> quotationList = new ArrayList<>(); public static void storeQuotation(Quotation quotation) { quotationList.add(quotation); } public static List<Quotation> getSpreadsList(boolean decreasing) { // 创建原始列表的副本,避免修改原数据 List<Quotation> sortedBySpread = new ArrayList<>(quotationList); // 定义按Spread升序排序的比较器 Comparator<Quotation> spreadComparator = (a, b) -> { // 计算每个对象的Spread:askPrice - bidPrice BigDecimal spreadA = a.getAskPrice().subtract(a.getBidPrice()); BigDecimal spreadB = b.getAskPrice().subtract(b.getBidPrice()); // 使用BigDecimal的compareTo方法比较,保证精度和正确性 return spreadA.compareTo(spreadB); }; // 根据参数选择升序或降序排序 Collections.sort(sortedBySpread, decreasing ? spreadComparator.reversed() : spreadComparator); return sortedBySpread; } } // 补充Quotation类的getter方法(原代码省略,必须实现才能访问属性) class Quotation { private final long id; private final BigDecimal askPrice; private final BigDecimal bidPrice; public Quotation(long id, BigDecimal bidPrice, BigDecimal askPrice) { this.id = id; this.askPrice = askPrice; this.bidPrice = bidPrice; } public BigDecimal getAskPrice() { return askPrice; } public BigDecimal getBidPrice() { return bidPrice; } // 可选:重写toString方便验证排序结果 @Override public String toString() { BigDecimal spread = askPrice.subtract(bidPrice); return String.format("id - %d. Bid - %s. Ask - %s. Spread = %s", id, bidPrice, askPrice, spread); } }
关键说明
- 列表副本保护原始数据:通过
new ArrayList<>(quotationList)创建副本,排序操作不会影响原始列表。 - 正确计算Spread:每个Quotation对象独立计算自身的Spread(
askPrice.subtract(bidPrice)),再进行两两比较。 - BigDecimal的compareTo方法:BigDecimal不能直接用算术运算符比较大小,
compareTo方法返回-1、0、1,完全符合Comparator的返回要求,同时保证精度不丢失。 - 简洁处理升降序:使用
spreadComparator.reversed()直接生成降序比较器,比排序后反转列表更高效。
验证结果
调用getSpreadsList(false)(升序)会得到如下排序结果:
id - 1003. Bid - 70. Ask - 71. Spread = 1 id - 1006. Bid - 92. Ask - 93. Spread = 1 id - 1004. Bid - 71. Ask - 73. Spread = 2 id - 1008. Bid - 90. Ask - 92. Spread = 2 id - 1001. Bid - 69. Ask - 72. Spread = 3 id - 1009. Bid - 92. Ask - 95. Spread = 3 id - 1002. Bid - 65. Ask - 69. Spread = 4 id - 1007. Bid - 94. Ask - 98. Spread = 4 id - 1000. Bid - 99. Ask - 104. Spread = 5 id - 1005. Bid - 90. Ask - 95. Spread = 5
调用getSpreadsList(true)(降序)则会得到完全相反的顺序。
内容的提问来源于stack exchange,提问作者Anatolii
相关产品推荐
相关产品推荐

