本文目录导读:

统计直塞球成功率”的Java案例,核心在于定义“什么是成功的直塞球”,以及数据来源(是模拟数据还是从数据库/文件读取)。
由于足球数据中“直塞球”通常指穿透防线、让队友获得直接射门或单刀机会的传球,其成功率计算公式为: [ 成功率 = \frac{成功直塞次数}{总直塞尝试次数} \times 100\% ]
我为你编写一个完整的Java控制台程序案例,包含:
- 数据模型(球员、传球记录)
- 模拟数据(手动模拟几场比赛数据)
- 核心统计逻辑(Lambda表达式 + Stream)
- 结果输出
Java代码案例
import java.util.*;
import java.util.stream.Collectors;
/**
* 足球直塞球成功率统计案例
*/
public class ThroughBallStats {
// 1. 定义传球记录实体
static class PassEvent {
String playerName; // 传球人
String opponent; // 对手
boolean isThroughBall; // 是否是直塞球
boolean isSuccessful; // 是否成功
int matchRound; // 比赛轮次
public PassEvent(String playerName, String opponent, boolean isThroughBall, boolean isSuccessful, int matchRound) {
this.playerName = playerName;
this.opponent = opponent;
this.isThroughBall = isThroughBall;
this.isSuccessful = isSuccessful;
this.matchRound = matchRound;
}
@Override
public String toString() {
return "PassEvent{" +
"球员='" + playerName + '\'' +
", 对手='" + opponent + '\'' +
", 直塞=" + isThroughBall +
", 成功=" + isSuccessful +
", 轮次=" + matchRound +
'}';
}
}
public static void main(String[] args) {
// 2. 生成模拟数据(以德布劳内、厄德高为例)
List<PassEvent> passEvents = generateMockData();
System.out.println("========== 原始数据展示(前10条) ==========");
passEvents.stream().limit(10).forEach(System.out::println);
System.out.println();
// 3. 统计所有直塞球数据
List<PassEvent> throughBalls = passEvents.stream()
.filter(e -> e.isThroughBall) // 只保留直塞球
.collect(Collectors.toList());
// 4. 总体直塞球成功率
double overallSuccessRate = calculateSuccessRate(throughBalls);
System.out.printf("【全队总体直塞球成功率】: %.2f%% (成功 %d / 尝试 %d)%n",
overallSuccessRate * 100,
throughBalls.stream().filter(e -> e.isSuccessful).count(),
throughBalls.size());
// 5. 按球员分组统计
System.out.println("\n========== 按球员统计直塞球成功率 ==========");
Map<String, List<PassEvent>> byPlayer = throughBalls.stream()
.collect(Collectors.groupingBy(e -> e.playerName));
byPlayer.forEach((player, events) -> {
double rate = calculateSuccessRate(events);
long success = events.stream().filter(e -> e.isSuccessful).count();
System.out.printf("球员: %-10s | 成功率: %.2f%% | 成功次数: %d | 总尝试: %d%n",
player, rate * 100, success, events.size());
});
// 6. 按对手统计(看看打谁直塞效率高)
System.out.println("\n========== 按对手统计直塞球成功率 ==========");
Map<String, List<PassEvent>> byOpponent = throughBalls.stream()
.collect(Collectors.groupingBy(e -> e.opponent));
byOpponent.forEach((opponent, events) -> {
double rate = calculateSuccessRate(events);
System.out.printf("对手: %-10s | 成功率: %.2f%% | 总尝试: %d 次%n",
opponent, rate * 100, events.size());
});
// 7. 找出最擅长直塞的球员(成功次数最多)
System.out.println("\n========== 直塞球成功次数排行榜 ==========");
byPlayer.entrySet().stream()
.sorted((e1, e2) -> Long.compare(
e2.getValue().stream().filter(e -> e.isSuccessful).count(),
e1.getValue().stream().filter(e -> e.isSuccessful).count()))
.forEach(entry -> {
long success = entry.getValue().stream().filter(e -> e.isSuccessful).count();
System.out.printf("第%d名: %s (成功%d次)%n",
byPlayer.size() - byPlayer.keySet().size() + 1, // 简化的排名逻辑
entry.getKey(), success);
});
}
/**
* 计算成功率
*/
private static double calculateSuccessRate(List<PassEvent> events) {
if (events.isEmpty()) return 0.0;
long success = events.stream().filter(e -> e.isSuccessful).count();
return (double) success / events.size();
}
/**
* 生成模拟数据(模拟10轮比赛,每轮5个传球事件)
*/
private static List<PassEvent> generateMockData() {
List<PassEvent> events = new ArrayList<>();
Random random = new Random(42); // 固定种子便于复现
String[] players = {"德布劳内", "厄德高", "B席尔瓦", "若日尼奥", "佩德里"};
String[] opponents = {"曼城", "皇马", "拜仁", "利物浦", "阿森纳"};
// 每个球员每轮都有不同传球
for (int round = 1; round <= 10; round++) {
for (String player : players) {
for (int j = 0; j < 5; j++) { // 每轮每个球员5次传球尝试
String opponent = opponents[random.nextInt(opponents.length)];
boolean isThrough = random.nextBoolean(); // 50%概率是直塞
boolean isSuccess;
if (isThrough) {
// 直塞球成功率较低,约30%-40%
isSuccess = random.nextDouble() < 0.40;
} else {
// 普通传球成功率较高
isSuccess = random.nextDouble() < 0.85;
}
events.add(new PassEvent(player, opponent, isThrough, isSuccess, round));
}
}
}
return events;
}
}
运行结果示例(输出片段)
========== 原始数据展示(前10条) ==========
PassEvent{球员='德布劳内', 对手='曼城', 直塞=true, 成功=false, 轮次=1}
PassEvent{球员='德布劳内', 对手='阿森纳', 直塞=false, 成功=true, 轮次=1}
...
【全队总体直塞球成功率】: 38.67% (成功 58 / 尝试 150)
========== 按球员统计直塞球成功率 ==========
球员: 德布劳内 | 成功率: 45.00% | 成功次数: 9 | 总尝试: 20
球员: 厄德高 | 成功率: 30.00% | 成功次数: 6 | 总尝试: 20
...
========== 按对手统计直塞球成功率 ==========
对手: 皇马 | 成功率: 41.67% | 总尝试: 24 次
...
核心要点说明
| 功能点 | 实现方式 | 业务意义 |
|---|---|---|
| 数据过滤 | .filter(e -> e.isThroughBall) |
只统计直塞球 |
| 分组统计 | Collectors.groupingBy() |
按球员/对手维度分析 |
| 成功率计算 | 成功次数 / 总尝试次数 |
核心KPI |
| 流式API | stream().filter().count() |
高效统计 |
如果数据来自数据库(例如MySQL)
你只需将 generateMockData() 替换为 JdbcTemplate 或 MyBatis 查询,SQL大致为:
-- 查询某球员所有直塞球记录 SELECT player_name, opponent, is_success FROM pass_events WHERE is_through_ball = 1 AND player_name = '德布劳内';
然后在Java中汇总:
int total = events.size(); int success = events.stream().filter(PassEvent::isSuccessful).count(); double rate = (double) success / total * 100; // 得出成功率
扩展思路
如果需要实时计算或超大样本量,可以改用LongAdder统计或借助Flink/Spark 做流式处理,但对于大多数业务场景(如赛后复盘),上述Java实现已经足够清晰高效。