足球比赛门将扑救次数统计案例
下面用一个完整的 Java 案例来统计多名门将的扑救次数,并找出"最忙"的门将。

需求分析
在一场足球赛事(或多场比赛)中,需要:
- 记录每位门将的扑救次数
- 统计总扑救数、平均扑救数
- 找出扑救次数最多(最忙)的门将
- 按扑救次数排序输出
完整代码实现
import java.util.*;
import java.util.stream.Collectors;
/**
* 门将扑救统计案例
*/
public class GoalkeeperSaveStats {
// 门将实体类
static class Goalkeeper {
private String name; // 门将姓名
private String team; // 所属球队
private int saveCount; // 扑救次数
public Goalkeeper(String name, String team, int saveCount) {
this.name = name;
this.team = team;
this.saveCount = saveCount;
}
public String getName() { return name; }
public String getTeam() { return team; }
public int getSaveCount() { return saveCount; }
@Override
public String toString() {
return String.format("%-10s(%s) 扑救 %d 次", name, team, saveCount);
}
}
public static void main(String[] args) {
// 1. 模拟一场比赛中各门将的扑救数据
List<Goalkeeper> keepers = new ArrayList<>();
keepers.add(new Goalkeeper("王大雷", "山东泰山", 6));
keepers.add(new Goalkeeper("颜骏凌", "上海海港", 3));
keepers.add(new Goalkeeper("刘殿座", "武汉三镇", 8));
keepers.add(new Goalkeeper("韩佳奇", "北京国安", 5));
keepers.add(new Goalkeeper("鲍亚雄", "上海申花", 2));
System.out.println("========== 原始扑救数据 ==========");
keepers.forEach(System.out::println);
// 2. 总扑救数
int totalSaves = keepers.stream()
.mapToInt(Goalkeeper::getSaveCount)
.sum();
System.out.println("\n总扑救次数: " + totalSaves);
// 3. 平均扑救数
double avg = keepers.stream()
.mapToInt(Goalkeeper::getSaveCount)
.average()
.orElse(0);
System.out.printf("平均扑救次数: %.2f%n", avg);
// 4. 找出"最忙"的门将(扑救次数最多)
Optional<Goalkeeper> busiest = keepers.stream()
.max(Comparator.comparingInt(Goalkeeper::getSaveCount));
busiest.ifPresent(k ->
System.out.println("\n🏆 最忙的门将: " + k.getName()
+ " (" + k.getTeam() + ") 扑救 " + k.getSaveCount() + " 次"));
// 5. 排序输出(从多到少)
System.out.println("\n========== 扑救排行 ==========");
List<Goalkeeper> sorted = keepers.stream()
.sorted(Comparator.comparingInt(Goalkeeper::getSaveCount).reversed())
.collect(Collectors.toList());
int rank = 1;
for (Goalkeeper k : sorted) {
System.out.println("第" + rank++ + "名: " + k);
}
// 6. 筛选出"忙碌"门将(扑救次数 >= 平均值)
System.out.println("\n========== 高于平均水平的门将 ==========");
keepers.stream()
.filter(k -> k.getSaveCount() >= avg)
.forEach(k -> System.out.println(k.getName() + " - 扑救 " + k.getSaveCount() + " 次"));
// 7. 按球队分组统计(多队场景)
System.out.println("\n========== 按球队汇总 ==========");
Map<String, Integer> teamTotal = keepers.stream()
.collect(Collectors.groupingBy(
Goalkeeper::getTeam,
Collectors.summingInt(Goalkeeper::getSaveCount)
));
teamTotal.forEach((team, count) ->
System.out.println(team + ": " + count + " 次"));
}
}
运行结果示例
========== 原始扑救数据 ==========
王大雷 (山东泰山) 扑救 6 次
颜骏凌 (上海海港) 扑救 3 次
刘殿座 (武汉三镇) 扑救 8 次
韩佳奇 (北京国安) 扑救 5 次
鲍亚雄 (上海申花) 扑救 2 次
总扑救次数: 24
平均扑救次数: 4.80
🏆 最忙的门将: 刘殿座 (武汉三镇) 扑救 8 次
========== 扑救排行 ==========
第1名: 刘殿座 (武汉三镇) 扑救 8 次
第2名: 王大雷 (山东泰山) 扑救 6 次
第3名: 韩佳奇 (北京国安) 扑救 5 次
第4名: 颜骏凌 (上海海港) 扑救 3 次
第5名: 鲍亚雄 (上海申花) 扑救 2 次
========== 高于平均水平的门将 ==========
刘殿座 - 扑救 8 次
王大雷 - 扑救 6 次
韩佳奇 - 扑救 5 次
========== 按球队汇总 ==========
上海申花: 2 次
北京国安: 5 次
山东泰山: 6 次
武汉三镇: 8 次
上海海港: 3 次
核心知识点解析
| 功能 | 使用的方法 | 说明 |
|---|---|---|
| 求和 | mapToInt().sum() |
统计总扑救次数 |
| 平均值 | average().orElse(0) |
计算场均扑救 |
| 最大值 | max(Comparator) |
找最忙门将 |
| 排序 | sorted() |
扑救排行 |
| 筛选 | filter() |
找出高于均值者 |
| 分组 | groupingBy() |
按球队汇总 |
扩展思路
- 多场比赛统计:把每场比赛的扑救数累加,用
Map<String, Integer>汇总。 - 读写文件:从 CSV 读取比赛数据,
王大雷,山东泰山,6。 - 按扑救率排名:加入"射正次数"字段,用
saveCount / shotsOnTarget计算扑救率,更公平评价门将表现。 - 平局处理:如果多个门将扑救次数相同,可以并列显示"最忙"。
更公平的"谁更忙"判据
单纯看扑救次数不够准确 —— 面对 20 次射正扑出 5 次,和面对 6 次射正扑出 5 次,前者其实更辛苦,可加一个字段:
class Goalkeeper {
String name;
int saveCount; // 扑救次数
int shotsOnTarget; // 面对射正次数
// 扑救率
double saveRate() {
return shotsOnTarget == 0 ? 0 : (double) saveCount / shotsOnTarget;
}
}
然后按 saveRate() 排序,就能得到"效率最高"的门将。
需要我把它改造成读取 CSV 文件或多场比赛汇总的版本吗?