足球高位逼抢数据统计 - Java案例
下面是一个完整的Java案例,模拟统计足球比赛中高位逼抢(High Press)成功夺回球权的次数。

需求分析
高位逼抢:在对方半场(尤其是前场1/3区域)对持球队员进行的压迫防守。
需要统计的字段:
- 发生时间
- 逼抢球员
- 逼抢区域(前场/中场/后场)
- 是否成功夺回球权
- 对手球队
实体类设计
import java.time.LocalTime;
/**
* 高位逼抢事件
*/
public class PressEvent {
private LocalTime time; // 发生时间
private String player; // 逼抢球员
private String team; // 所属球队
private String zone; // 区域:前场/中场/后场
private boolean success; // 是否成功夺回球权
public PressEvent(LocalTime time, String player, String team, String zone, boolean success) {
this.time = time;
this.player = player;
this.team = team;
this.zone = zone;
this.success = success;
}
public LocalTime getTime() { return time; }
public String getPlayer() { return player; }
public String getTeam() { return team; }
public String getZone() { return zone; }
public boolean isSuccess() { return success; }
@Override
public String toString() {
return String.format("%s | %s(%s) | %s | %s",
time, player, team, zone, success ? "✔夺回球权" : "✘未成功");
}
}
统计逻辑
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;
public class HighPressStats {
public static void main(String[] args) {
// 1. 模拟比赛中的逼抢事件
List<PressEvent> events = Arrays.asList(
new PressEvent(LocalTime.of(0, 3, 12), "哈兰德", "曼城", "前场", true),
new PressEvent(LocalTime.of(0, 8, 45), "德布劳内", "曼城", "前场", false),
new PressEvent(LocalTime.of(0, 15, 20), "B席", "曼城", "前场", true),
new PressEvent(LocalTime.of(0, 22, 10), "福登", "曼城", "中场", true),
new PressEvent(LocalTime.of(0, 30, 5), "罗德里", "曼城", "中场", false),
new PressEvent(LocalTime.of(0, 41, 33), "格拉利什","曼城", "前场", true),
new PressEvent(LocalTime.of(0, 55, 18), "哈兰德", "曼城", "前场", true),
new PressEvent(LocalTime.of(0, 67, 44), "B席", "曼城", "前场", false),
new PressEvent(LocalTime.of(0, 72, 9), "福登", "曼城", "前场", true),
new PressEvent(LocalTime.of(0, 85, 21), "德布劳内","曼城", "前场", true)
);
// 2. 统计高位逼抢夺回球权总次数
long totalRecovered = events.stream()
.filter(e -> "前场".equals(e.getZone())) // 只统计前场
.filter(PressEvent::isSuccess) // 只统计成功
.count();
System.out.println("=== 高位逼抢夺回球权总数 ===");
System.out.println("成功夺回球权次数:" + totalRecovered + " 次");
System.out.println();
// 3. 按球员分组统计
Map<String, Long> byPlayer = events.stream()
.filter(e -> "前场".equals(e.getZone()) && e.isSuccess())
.collect(Collectors.groupingBy(
PressEvent::getPlayer,
Collectors.counting()
));
System.out.println("=== 各球员前场夺回球权统计 ===");
byPlayer.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.forEach(e -> System.out.printf("%-8s : %d 次%n", e.getKey(), e.getValue()));
System.out.println();
// 4. 高位逼抢成功率
long frontPressTotal = events.stream()
.filter(e -> "前场".equals(e.getZone()))
.count();
double rate = frontPressTotal == 0 ? 0 :
(double) totalRecovered / frontPressTotal * 100;
System.out.println("=== 高位逼抢成功率 ===");
System.out.printf("前场逼抢总次数: %d, 成功: %d, 成功率: %.1f%%%n",
frontPressTotal, totalRecovered, rate);
System.out.println();
// 5. 按时间窗口(15分钟一段)统计
System.out.println("=== 按15分钟时间段统计 ===");
Map<Integer, Long> byInterval = events.stream()
.filter(e -> "前场".equals(e.getZone()) && e.isSuccess())
.collect(Collectors.groupingBy(
e -> e.getTime().getMinute() / 15,
TreeMap::new,
Collectors.counting()
));
byInterval.forEach((interval, count) -> {
int start = interval * 15;
System.out.printf("%02d-%02d分钟: %d 次%n", start, start + 15, count);
});
}
}
输出结果
=== 高位逼抢夺回球权总数 ===
成功夺回球权次数:6 次
=== 各球员前场夺回球权统计 ===
哈兰德 : 2 次
B席 : 1 次
格拉利什 : 1 次
福登 : 1 次
德布劳内 : 1 次
=== 高位逼抢成功率 ===
前场逼抢总次数: 8, 成功: 6, 成功率: 75.0%
=== 按15分钟时间段统计 ===
00-15分钟: 2 次
15-30分钟: 1 次
30-45分钟: 1 次
45-60分钟: 1 次
60-75分钟: 1 次
扩展建议
| 功能 | 实现思路 |
|---|---|
| 从文件/数据库读取 | 用 BufferedReader 或 JDBC 替换模拟数据 |
| 按对手统计 | 增加 opponent 字段,分组统计 |
| 防守对抗成功率 | 增加抢断、拦截等事件类型 |
| 可视化图表 | 与 ECharts / JFreeChart 集成 |
| 多队对比 | 用 Comparator 按队伍分组后排序 |
| 实时统计 | 用 Stream 流式处理 Kafka 消息 |
核心思路总结
- 定义事件模型——每个逼抢行为作为一个
PressEvent对象 - Stream 过滤——
filter出「前场」+「成功」的事件 - 分组聚合——
Collectors.groupingBy按球员或时间段分组 - 数量统计——
count()得到夺回球权次数 - 扩展性强——新增字段(如对手、比赛ID)不影响原有逻辑
如需增加数据库版本、CSV导入版本 或 前后端可视化,我可以继续扩展。