门球短传配合成功率统计 - Java 案例
下面是一个完整的 Java 案例,用于统计门球比赛中短传配合的成功率,包含数据模型、统计逻辑和测试示例。

需求分析
门球短传配合统计需要记录:
- 传球方(球员编号)
- 接球方
- 传球距离(短传一般 ≤ 5 米)
- 传球结果(成功 / 失败)
- 失败原因(可选:出界、被截、接球失误等)
统计指标:
- 总短传次数
- 成功次数 / 失败次数
- 成功率 = 成功次数 / 总次数 × 100%
- 按球员细分成功率
- 失败原因分布
代码实现
1 枚举与实体类
import java.util.*;
import java.util.stream.Collectors;
// 传球结果枚举
enum PassResult {
SUCCESS("成功"),
FAIL_OUT("出界"),
FAIL_INTERCEPT("被截"),
FAIL_RECEIVE("接球失误");
private final String desc;
PassResult(String desc) { this.desc = desc; }
public String getDesc() { return desc; }
public boolean isSuccess() { return this == SUCCESS; }
}
// 短传记录
class ShortPass {
private final String passer; // 传球球员
private final String receiver; // 接球球员
private final double distance; // 距离(米)
private final PassResult result;
public ShortPass(String passer, String receiver, double distance, PassResult result) {
this.passer = passer;
this.receiver = receiver;
this.distance = distance;
this.result = result;
}
public String getPasser() { return passer; }
public String getReceiver() { return receiver; }
public double getDistance() { return distance; }
public PassResult getResult() { return result; }
public boolean isSuccess() { return result.isSuccess(); }
}
2 统计器
class ShortPassStatistics {
private static final double SHORT_PASS_MAX = 5.0; // 短传阈值(米)
private final List<ShortPass> records = new ArrayList<>();
/** 添加一条传球记录(自动过滤非短传) */
public void addRecord(ShortPass pass) {
if (pass.getDistance() <= SHORT_PASS_MAX) {
records.add(pass);
}
}
public void addRecords(List<ShortPass> list) {
list.forEach(this::addRecord);
}
/** 总次数 */
public int totalCount() { return records.size(); }
/** 成功次数 */
public long successCount() {
return records.stream().filter(ShortPass::isSuccess).count();
}
/** 整体成功率(%) */
public double successRate() {
if (records.isEmpty()) return 0.0;
return successCount() * 100.0 / records.size();
}
/** 按球员统计成功率 */
public Map<String, Double> successRateByPlayer() {
Map<String, List<ShortPass>> grouped = records.stream()
.collect(Collectors.groupingBy(ShortPass::getPasser));
Map<String, Double> result = new LinkedHashMap<>();
grouped.forEach((player, list) -> {
long ok = list.stream().filter(ShortPass::isSuccess).count();
result.put(player, ok * 100.0 / list.size());
});
return result;
}
/** 失败原因分布 */
public Map<PassResult, Long> failureDistribution() {
return records.stream()
.filter(p -> !p.isSuccess())
.collect(Collectors.groupingBy(ShortPass::getResult, Collectors.counting()));
}
/** 打印完整报告 */
public void printReport() {
System.out.println("===== 门球短传配合统计报告 =====");
System.out.printf("总短传次数 : %d%n", totalCount());
System.out.printf("成功次数 : %d%n", successCount());
System.out.printf("失败次数 : %d%n", totalCount() - successCount());
System.out.printf("整体成功率 : %.2f%%%n", successRate());
System.out.println("\n--- 球员成功率 ---");
successRateByPlayer().forEach((p, r) ->
System.out.printf("%-6s : %.2f%%%n", p, r));
System.out.println("\n--- 失败原因分布 ---");
failureDistribution().forEach((reason, cnt) ->
System.out.printf("%-8s : %d 次%n", reason.getDesc(), cnt));
}
}
3 测试示例
public class GateBallDemo {
public static void main(String[] args) {
List<ShortPass> data = Arrays.asList(
new ShortPass("张1", "李2", 3.5, PassResult.SUCCESS),
new ShortPass("张1", "王3", 4.2, PassResult.SUCCESS),
new ShortPass("张1", "李2", 2.8, PassResult.FAIL_OUT),
new ShortPass("李2", "张1", 4.5, PassResult.SUCCESS),
new ShortPass("李2", "王3", 1.9, PassResult.FAIL_INTERCEPT),
new ShortPass("王3", "张1", 3.0, PassResult.SUCCESS),
new ShortPass("王3", "李2", 4.8, PassResult.FAIL_RECEIVE),
new ShortPass("王3", "张1", 2.2, PassResult.SUCCESS),
new ShortPass("张1", "王3", 4.9, PassResult.SUCCESS),
// 下面这条距离 6.5 米,属于中长传,会被过滤
new ShortPass("李2", "王3", 6.5, PassResult.SUCCESS)
);
ShortPassStatistics stats = new ShortPassStatistics();
stats.addRecords(data);
stats.printReport();
}
}
运行结果
===== 门球短传配合统计报告 =====
总短传次数 : 9
成功次数 : 6
失败次数 : 3
整体成功率 : 66.67%
--- 球员成功率 ---
张1 : 75.00%
李2 : 50.00%
王3 : 66.67%
--- 失败原因分布 ---
出界 : 1 次
被截 : 1 次
接球失误 : 1 次
第 10 条记录(距离 6.5 米)被自动过滤,符合"短传 ≤ 5 米"的定义。
扩展建议
若想做成完整系统,可考虑:
| 扩展方向 | 说明 |
|---|---|
| 文件读取 | 从 CSV/Excel 读取比赛记录,用 BufferedReader 或 Apache POI |
| 时间段统计 | 给记录加 LocalDateTime,按半场、加时统计 |
| 双人配合排行 | 用 passer + receiver 作为 key 统计默契度 |
| 可视化 | 导出 JSON,用 ECharts 展示成功率趋势图 |
| 异常校验 | 校验传球双方不能相同、距离非负 |
| 数据库 | 用 MyBatis / JPA 持久化,支持历史对抗查询 |
核心思路:把每条短传建模为对象 → 用 Stream 按整体 / 按球员 / 按失败原因分组聚合 → 成功数 / 总数 × 100 得到成功率,逻辑清晰,易于扩展。
如果需要我把它改成从文件读取数据或按半场分段统计的版本,可以告诉我 😊