Java案例:统计任意球直接得分次数
下面通过一个完整的Java案例,演示如何统计足球比赛中任意球直接得分的次数。

需求分析
在足球比赛中,任意球分为两种得分方式:
- 直接任意球得分:任意球直接射入球门(不经过其他球员触碰)
- 间接任意球得分:任意球发出后经其他球员触碰后进球
我们需要从比赛事件记录中,统计出任意球直接得分的次数。
完整代码实现
import java.util.ArrayList;
import java.util.List;
/**
* 足球比赛事件记录
*/
class MatchEvent {
private String playerName; // 球员姓名
private String teamName; // 球队名称
private EventType eventType; // 事件类型
private int minute; // 发生分钟
public MatchEvent(String playerName, String teamName, EventType eventType, int minute) {
this.playerName = playerName;
this.teamName = teamName;
this.eventType = eventType;
this.minute = minute;
}
public String getPlayerName() { return playerName; }
public String getTeamName() { return teamName; }
public EventType getEventType() { return eventType; }
public int getMinute() { return minute; }
@Override
public String toString() {
return String.format("%d' [%s] %s - %s", minute, teamName, playerName, eventType);
}
}
/**
* 事件类型枚举
*/
enum EventType {
FREE_KICK_GOAL, // 任意球直接得分
FREE_KICK_ASSIST, // 任意球助攻(间接得分)
FREE_KICK_MISS, // 任意球射失
PENALTY_GOAL, // 点球得分
NORMAL_GOAL // 普通进球
}
/**
* 任意球得分统计器
*/
class FreeKickStatistics {
private List<MatchEvent> events = new ArrayList<>();
public void addEvent(MatchEvent event) {
events.add(event);
}
/**
* 统计任意球直接得分总次数
*/
public long countDirectFreeKickGoals() {
return events.stream()
.filter(e -> e.getEventType() == EventType.FREE_KICK_GOAL)
.count();
}
/**
* 按球队统计任意球直接得分
*/
public java.util.Map<String, Long> countByTeam() {
return events.stream()
.filter(e -> e.getEventType() == EventType.FREE_KICK_GOAL)
.collect(java.util.stream.Collectors.groupingBy(
MatchEvent::getTeamName,
java.util.stream.Collectors.counting()
));
}
/**
* 按球员统计任意球直接得分
*/
public java.util.Map<String, Long> countByPlayer() {
return events.stream()
.filter(e -> e.getEventType() == EventType.FREE_KICK_GOAL)
.collect(java.util.stream.Collectors.groupingBy(
MatchEvent::getPlayerName,
java.util.stream.Collectors.counting()
));
}
/**
* 打印所有任意球直接得分事件
*/
public void printDirectFreeKickGoals() {
System.out.println("=== 任意球直接得分事件列表 ===");
events.stream()
.filter(e -> e.getEventType() == EventType.FREE_KICK_GOAL)
.forEach(System.out::println);
}
}
/**
* 主程序:演示任意球得分统计
*/
public class FreeKickDemo {
public static void main(String[] args) {
FreeKickStatistics stats = new FreeKickStatistics();
// 模拟一场比赛的事件记录
stats.addEvent(new MatchEvent("梅西", "阿根廷", EventType.FREE_KICK_GOAL, 23));
stats.addEvent(new MatchEvent("C罗", "葡萄牙", EventType.FREE_KICK_GOAL, 45));
stats.addEvent(new MatchEvent("内马尔", "巴西", EventType.FREE_KICK_MISS, 60));
stats.addEvent(new MatchEvent("梅西", "阿根廷", EventType.FREE_KICK_ASSIST, 72)); // 间接得分不算
stats.addEvent(new MatchEvent("姆巴佩", "法国", EventType.NORMAL_GOAL, 78));
stats.addEvent(new MatchEvent("贝克汉姆", "英格兰", EventType.FREE_KICK_GOAL, 85));
stats.addEvent(new MatchEvent("梅西", "阿根廷", EventType.FREE_KICK_GOAL, 90));
// 1. 统计任意球直接得分总次数
long total = stats.countDirectFreeKickGoals();
System.out.println("任意球直接得分总次数: " + total);
// 2. 打印详细事件
System.out.println();
stats.printDirectFreeKickGoals();
// 3. 按球队统计
System.out.println("\n=== 按球队统计 ===");
stats.countByTeam().forEach((team, count) ->
System.out.println(team + ": " + count + " 次"));
// 4. 按球员统计
System.out.println("\n=== 按球员统计 ===");
stats.countByPlayer().forEach((player, count) ->
System.out.println(player + ": " + count + " 次"));
}
}
运行结果
任意球直接得分总次数: 4
=== 任意球直接得分事件列表 ===
23' [阿根廷] 梅西 - FREE_KICK_GOAL
45' [葡萄牙] C罗 - FREE_KICK_GOAL
85' [英格兰] 贝克汉姆 - FREE_KICK_GOAL
90' [阿根廷] 梅西 - FREE_KICK_GOAL
=== 按球队统计 ===
葡萄牙: 1 次
英格兰: 1 次
阿根廷: 2 次
=== 按球员统计 ===
梅西: 2 次
C罗: 1 次
贝克汉姆: 1 次
核心思路解析
事件建模
将每个比赛事件抽象为 MatchEvent 对象,用 EventType 枚举区分事件类型,FREE_KICK_GOAL 表示任意球直接得分。
关键区分点
// 直接得分 vs 间接得分 vs 射失 FREE_KICK_GOAL, // ✅ 直接射入 → 计数 FREE_KICK_ASSIST, // ❌ 助攻(间接) → 不计数 FREE_KICK_MISS // ❌ 射失 → 不计数
使用Stream过滤统计
events.stream()
.filter(e -> e.getEventType() == EventType.FREE_KICK_GOAL)
.count();
分组统计
使用 Collectors.groupingBy 按球队/球员维度分类计数。
扩展建议
如果需要从真实数据源读取,可以考虑:
// 从文本文件读取,每行格式:球员,球队,事件类型,分钟
public void loadFromFile(String path) throws IOException {
Files.lines(Paths.get(path))
.map(line -> line.split(","))
.forEach(arr -> addEvent(new MatchEvent(
arr[0], arr[1], EventType.valueOf(arr[2]), Integer.parseInt(arr[3])
)));
}
如果想要统计整个赛季的数据,只需将 FreeKickStatistics 中的 events 不断累积,最后调用统计方法即可,逻辑完全不变。