Java 案例:统计回传次数反映保守程度
"回传次数"这个概念在不同场景有不同含义,下面给出一个通用可复用的 Java 实现方案,你可以根据实际业务替换字段。

场景理解
回传次数"指某个对象在某段时间内被上报/回调/重试的次数,次数越多,说明:
- 系统越"保守"(宁愿多次确认、多次重发,也不愿漏掉)
- 或用户行为越"保守"(反复操作、犹豫)
下面以消息回传(回调)统计为例,通过回传频次来计算"保守度"。
核心代码
数据模型
import java.time.LocalDateTime;
/** 一次回传记录 */
public class CallbackRecord {
private String bizId; // 业务ID(如订单号、消息ID)
private String userId; // 用户/客户端标识
private LocalDateTime time; // 回传时间
private boolean success; // 是否成功
public CallbackRecord(String bizId, String userId, LocalDateTime time, boolean success) {
this.bizId = bizId;
this.userId = userId;
this.time = time;
this.success = success;
}
// getter 省略...
public String getUserId() { return userId; }
public String getBizId() { return bizId; }
public LocalDateTime getTime() { return time; }
public boolean isSuccess() { return success; }
}
统计服务
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
public class CallbackStatsService {
/**
* 按用户统计每个业务ID的平均回传次数
* 回传次数越高 -> 保守度越高
*/
public Map<String, UserConservativeScore> analyze(List<CallbackRecord> records,
LocalDateTime windowStart,
LocalDateTime windowEnd) {
// 1. 过滤时间窗口
List<CallbackRecord> filtered = records.stream()
.filter(r -> !r.getTime().isBefore(windowStart)
&& !r.getTime().isAfter(windowEnd))
.collect(Collectors.toList());
// 2. 按 userId -> bizId 分组计数
Map<String, Map<String, Long>> userBizCount = filtered.stream()
.collect(Collectors.groupingBy(
CallbackRecord::getUserId,
Collectors.groupingBy(CallbackRecord::getBizId, Collectors.counting())
));
// 3. 计算保守度指标
Map<String, UserConservativeScore> result = new HashMap<>();
for (Map.Entry<String, Map<String, Long>> e : userBizCount.entrySet()) {
String userId = e.getKey();
Collection<Long> counts = e.getValue().values();
double avg = counts.stream().mapToLong(Long::longValue).average().orElse(0);
long max = counts.stream().mapToLong(Long::longValue).max().orElse(0);
long total = counts.stream().mapToLong(Long::longValue).sum();
// 保守度 = 平均回传次数(可自定义权重公式)
double conservativeScore = calcScore(avg, max);
result.put(userId, new UserConservativeScore(
userId, e.getValue().size(), total, avg, max, conservativeScore));
}
return result;
}
/** 保守度评分:可替换为业务公式 */
private double calcScore(double avg, long max) {
// 示例:平均次数占 70%,最大次数占 30%
return avg * 0.7 + max * 0.3;
}
}
结果对象
public class UserConservativeScore {
private String userId;
private int bizCount; // 涉及业务数
private long totalCallbacks; // 总回传次数
private double avgCallbacks; // 平均每个业务回传次数
private long maxCallbacks; // 单业务最大回传次数
private double score; // 保守度评分
public UserConservativeScore(String userId, int bizCount, long totalCallbacks,
double avgCallbacks, long maxCallbacks, double score) {
this.userId = userId;
this.bizCount = bizCount;
this.totalCallbacks = totalCallbacks;
this.avgCallbacks = avgCallbacks;
this.maxCallbacks = maxCallbacks;
this.score = score;
}
// toString 省略...
}
测试用例
public class Demo {
public static void main(String[] args) {
LocalDateTime base = LocalDateTime.now();
List<CallbackRecord> records = List.of(
// 用户A:3个业务,回传次数多 -> 保守
new CallbackRecord("order1", "A", base.minusMinutes(10), true),
new CallbackRecord("order1", "A", base.minusMinutes(9), false),
new CallbackRecord("order1", "A", base.minusMinutes(8), true),
new CallbackRecord("order2", "A", base.minusMinutes(7), true),
new CallbackRecord("order2", "A", base.minusMinutes(6), true),
new CallbackRecord("order3", "A", base.minusMinutes(5), true),
// 用户B:每个业务只回传一次 -> 不保守
new CallbackRecord("order4", "B", base.minusMinutes(10), true),
new CallbackRecord("order5", "B", base.minusMinutes(9), true)
);
CallbackStatsService svc = new CallbackStatsService();
Map<String, UserConservativeScore> r = svc.analyze(
records, base.minusHours(1), base);
r.values().stream()
.sorted(Comparator.comparingDouble(UserConservativeScore::getScore).reversed())
.forEach(s -> System.out.printf(
"用户=%s 业务数=%d 总回传=%d 平均=%.2f 最大=%d 保守度=%.2f%n",
s.getUserId(), s.getBizCount(), s.getTotalCallbacks(),
s.getAvgCallbacks(), s.getMaxCallbacks(), s.getScore()));
}
}
输出示例:
用户=A 业务数=3 总回传=6 平均=2.00 最大=3 保守度=2.30
用户=B 业务数=2 总回传=2 平均=1.00 最大=1 保守度=1.00
设计要点
| 要点 | 说明 |
|---|---|
| 分组维度 | 按 userId/bizId 分组,可换成设备、渠道、接口等 |
| 时间窗口 | 用 windowStart/End 隔离统计周期,避免历史数据干扰 |
| 评分公式 | calcScore 可自定义,如加入失败重试权重、时间衰减等 |
| 流式处理 | stream().collect(groupingBy(...counting())) 天然支持大数据量 |
| 扩展性 | 若数据量大,可改用 ConcurrentHashMap + 分段统计,或落 Redis 计数 |
如何"反映保守程度"
- 平均回传次数 ↑ → 系统/用户倾向多次确认 → 保守
- 单业务最大回传次数 ↑ → 存在极端重试行为 → 风险规避倾向强
- 失败后的重试率 ↑ → 更保守(宁重不漏)
如果需要按接口维度、设备维度或加入失败重试权重,告诉我具体业务场景,我可以再给出对应的公式和代码。