Java 案例:统计"挑球过人"次数
下面给你一个完整的 Java 案例,模拟统计足球比赛中"挑球过人"的技术动作次数,并判断多不多。

需求分析
- 从比赛事件数据中筛选出 "挑球过人" 类型的事件
- 统计总次数
- 按球员分组统计
- 判断次数"多不多"(设定阈值)
完整代码
import java.util.*;
import java.util.stream.Collectors;
/**
* 统计挑球过人次数
*/
public class DribbleStatsDemo {
// 事件类型枚举
enum ActionType {
PASS, // 传球
SHOT, // 射门
TACKLE, // 抢断
NUTMEG, // 穿裆过人
RAINBOW_FLICK, // 彩虹过人
CHIP_DRIBBLE // 挑球过人 ⭐
}
// 比赛事件
static class MatchEvent {
String player;
ActionType type;
int minute;
MatchEvent(String player, ActionType type, int minute) {
this.player = player;
this.type = type;
this.minute = minute;
}
}
public static void main(String[] args) {
// 1. 模拟比赛事件数据
List<MatchEvent> events = List.of(
new MatchEvent("梅西", ActionType.CHIP_DRIBBLE, 12),
new MatchEvent("梅西", ActionType.CHIP_DRIBBLE, 35),
new MatchEvent("梅西", ActionType.PASS, 40),
new MatchEvent("内马尔", ActionType.CHIP_DRIBBLE, 8),
new MatchEvent("内马尔", ActionType.NUTMEG, 20),
new MatchEvent("内马尔", ActionType.SHOT, 55),
new MatchEvent("姆巴佩", ActionType.CHIP_DRIBBLE, 30),
new MatchEvent("姆巴佩", ActionType.CHIP_DRIBBLE, 62),
new MatchEvent("姆巴佩", ActionType.CHIP_DRIBBLE, 78),
new MatchEvent("姆巴佩", ActionType.TACKLE, 85),
new MatchEvent("维尼修斯", ActionType.RAINBOW_FLICK, 25),
new MatchEvent("维尼修斯", ActionType.CHIP_DRIBBLE, 70)
);
// 2. 筛选所有挑球过人事件
List<MatchEvent> chipDribbles = events.stream()
.filter(e -> e.type == ActionType.CHIP_DRIBBLE)
.collect(Collectors.toList());
// 3. 总次数统计
int total = chipDribbles.size();
System.out.println("=== 挑球过人总次数:" + total + " 次 ===");
// 4. 按球员分组统计(降序)
Map<String, Long> byPlayer = chipDribbles.stream()
.collect(Collectors.groupingBy(
e -> e.player,
Collectors.counting()
));
System.out.println("\n=== 各球员挑球过人次数 ===");
byPlayer.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.forEach(en -> System.out.printf("%-8s : %d 次%n",
en.getKey(), en.getValue()));
// 5. 判断"多不多"
// 规则:单场 >= 5 次 -> 多;< 3 次 -> 少;其余 -> 一般
System.out.println("\n=== 多不多判断 ===");
System.out.println("全队总次数评价:" + judge(total, 5, 3));
// 单球员评价
String topPlayer = byPlayer.entrySet().stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey).orElse("无");
long topCount = byPlayer.getOrDefault(topPlayer, 0L);
System.out.printf("表现最突出的球员:%s(%d 次)→ %s%n",
topPlayer, topCount, judge(topCount, 3, 2));
// 6. 附加信息:按时间分布(可选)
System.out.println("\n=== 挑球过人发生时间点 ===");
chipDribbles.stream()
.sorted(Comparator.comparingInt(e -> e.minute))
.forEach(e -> System.out.printf("%2d' %s%n", e.minute, e.player));
}
/**
* 判断次数的"多不多"
* @param count 实际次数
* @param high 高阈值
* @param low 低阈值
*/
private static String judge(int count, int high, int low) {
if (count >= high) return "🔝 多!技术亮眼";
if (count < low) return "🔻 少,需加强";
return "⚖️ 一般水平";
}
}
运行输出示例
=== 挑球过人总次数:6 次 ===
=== 各球员挑球过人次数 ===
梅西 : 2 次
姆巴佩 : 3 次
内马尔 : 1 次
维尼修斯 : 1 次
=== 多不多判断 ===
全队总次数评价:🔝 多!技术亮眼
表现最突出的球员:姆巴佩(3 次)→ 🔝 多!技术亮眼
=== 挑球过人发生时间点 ===
8' 内马尔
12' 梅西
30' 姆巴佩
35' 梅西
62' 姆巴佩
70' 维尼修斯
78' 姆巴佩
关键点讲解
| 步骤 | 技术点 | 说明 |
|---|---|---|
| 数据建模 | 内部类 + 枚举 | 用 ActionType 枚举约束事件类型,避免字符串硬编码 |
| 筛选 | Stream.filter |
只保留 CHIP_DRIBBLE 事件 |
| 分组统计 | Collectors.groupingBy + counting |
一句话完成按球员聚合 |
| 排序 | comparingByValue().reversed() |
排行榜按次数降序 |
| 判定 | 自定义 judge 方法 |
阈值参数化,方便调整(比如单场 5 次算多) |
扩展思路
- 真实数据:从 CSV / JSON / 数据库读取
MatchEvent,替换List.of(...)即可。 - 看比赛势头:结合时间轴,若某球员连续 10 分钟挑球 ≥ 2 次,可标记为"状态爆发"。
- 加权评分:
挑球过人分 3 级(成功过掉 1 人 / 2 人成功 → 高分),用Map<String,Integer>更精准。 - 阈值可配置:把
high、low放进配置文件(application.yml),便于不同联赛标准差异。
需要我改成 从 CSV 文件读取数据 或 统计成功率(挑球过人成功/失败) 的版本吗?