java案例统计单刀球成功率是多少?

wen java案例 2

用Java统计单刀球成功率

下面我用一个完整的Java案例来演示如何统计足球单刀球成功率,会包含数据模型、业务逻辑、多种统计方式(总体/按球员/按位置等)。

java案例统计单刀球成功率是多少?

需求分析

单刀球成功率 = 进球数 / 单刀球总数 × 100%

需要统计的维度:

  • 总体单刀成功率
  • 每个球员的单刀成功率
  • 可能还要区分联赛 / 杯赛

代码实现

定义实体类

import java.util.*;
/**
 * 单刀球记录
 */
class SingleShot {
    private String playerName;   // 球员姓名
    private String position;     // 位置:FW/MF/DF
    private boolean isGoal;      // 是否进球
    private String competition;  // 赛事:联赛/杯赛
    public SingleShot(String playerName, String position, boolean isGoal, String competition) {
        this.playerName = playerName;
        this.position = position;
        this.isGoal = isGoal;
        this.competition = competition;
    }
    public String getPlayerName() { return playerName; }
    public String getPosition()   { return position; }
    public boolean isGoal()       { return isGoal; }
    public String getCompetition(){ return competition; }
}

工具类:计算成功率

class StatsUtil {
    /**
     * 计算成功率 = 进球数 / 总数 * 100
     */
    public static double successRate(long goals, long total) {
        if (total == 0) return 0.0;
        return goals * 100.0 / total;
    }
    /**
     * 保留两位小数
     */
    public static double round2(double value) {
        return Math.round(value * 100.0) / 100.0;
    }
}

主程序:多种统计方式

import java.util.*;
import java.util.stream.Collectors;
public class SingleShotStatsDemo {
    public static void main(String[] args) {
        // ===== 1. 模拟数据 =====
        List<SingleShot> data = Arrays.asList(
            new SingleShot("梅西",   "FW", true,  "联赛"),
            new SingleShot("梅西",   "FW", false, "联赛"),
            new SingleShot("梅西",   "FW", true,  "杯赛"),
            new SingleShot("姆巴佩", "FW", true,  "联赛"),
            new SingleShot("姆巴佩", "FW", true,  "联赛"),
            new SingleShot("姆巴佩", "FW", false, "杯赛"),
            new SingleShot("哈兰德", "FW", true,  "联赛"),
            new SingleShot("哈兰德", "FW", true,  "联赛"),
            new SingleShot("哈兰德", "FW", true,  "杯赛"),
            new SingleShot("德布劳内","MF", false, "联赛"),
            new SingleShot("德布劳内","MF", true,  "联赛"),
            new SingleShot("维尼修斯","FW", false, "联赛"),
            new SingleShot("维尼修斯","FW", true,  "联赛")
        );
        // ===== 2. 总体单刀成功率 =====
        long total = data.size();
        long goals = data.stream().filter(SingleShot::isGoal).count();
        double overall = StatsUtil.round2(StatsUtil.successRate(goals, total));
        System.out.printf("【总体】单刀总数=%d, 进球=%d, 成功率=%.2f%%%n%n",
                total, goals, overall);
        // ===== 3. 按球员统计 =====
        System.out.println("【按球员统计】");
        Map<String, List<SingleShot>> byPlayer =
                data.stream().collect(Collectors.groupingBy(SingleShot::getPlayerName));
        // 按成功率降序输出
        byPlayer.entrySet().stream()
                .map(e -> {
                    long g = e.getValue().stream().filter(SingleShot::isGoal).count();
                    long t = e.getValue().size();
                    double rate = StatsUtil.round2(StatsUtil.successRate(g, t));
                    return new String[]{e.getKey(), String.valueOf(g),
                            String.valueOf(t), String.format("%.2f%%", rate)};
                })
                .sorted((a, b) -> Double.compare(
                        Double.parseDouble(b[3].replace("%", "")),
                        Double.parseDouble(a[3].replace("%", ""))))
                .forEach(a -> System.out.printf("  %-8s 进球=%-2s 总数=%-2s 成功率=%s%n",
                        a[0], a[1], a[2], a[3]));
        // ===== 4. 按赛事统计 =====
        System.out.println("\n【按赛事统计】");
        Map<String, List<SingleShot>> byComp =
                data.stream().collect(Collectors.groupingBy(SingleShot::getCompetition));
        byComp.forEach((comp, list) -> {
            long g = list.stream().filter(SingleShot::isGoal).count();
            double rate = StatsUtil.round2(StatsUtil.successRate(g, list.size()));
            System.out.printf("  %-4s 进球=%d 总数=%d 成功率=%.2f%%%n",
                    comp, g, list.size(), rate);
        });
        // ===== 5. 按位置统计 =====
        System.out.println("\n【按位置统计】");
        Map<String, List<SingleShot>> byPos =
                data.stream().collect(Collectors.groupingBy(SingleShot::getPosition));
        byPos.forEach((pos, list) -> {
            long g = list.stream().filter(SingleShot::isGoal).count();
            double rate = StatsUtil.round2(StatsUtil.successRate(g, list.size()));
            System.out.printf("  %-3s 进球=%d 总数=%d 成功率=%.2f%%%n",
                    pos, g, list.size(), rate);
        });
    }
}

运行结果

【总体】单刀总数=13, 进球=9, 成功率=69.23%
【按球员统计】
  哈兰德   进球=3  总数=3  成功率=100.00%
  姆巴佩   进球=2  总数=3  成功率=66.67%
  梅西     进球=2  总数=3  成功率=66.67%
  维尼修斯 进球=1  总数=2  成功率=50.00%
  德布劳内 进球=1  总数=2  成功率=50.00%
【按赛事统计】
  联赛 进球=6 总数=8 成功率=75.00%
  杯赛 进球=3 总数=5 成功率=60.00%
【按位置统计】
  FW  进球=8 总数=10 成功率=80.00%
  MF  进球=1 总数=2  成功率=50.00%

关键点说明

要点 说明
公式 成功率 = 进球数 / 单刀总数 × 100%
除零保护 total == 0 时返回 0,避免 NaN
分组统计 使用 Stream 的 groupingBy 按球员/赛事/位置聚合
排序 用 sorted 对成功率降序排列,便于找出效率最高球员
格式化 用 Math.round 或 String.format("%.2f%%") 保留两位小数

扩展建议

  1. 概率论视角:如果单刀成功率服从二项分布,可用 BinomialDistribution(Apache Commons Math)计算置信区间,判断样本量是否足够。
  2. 滑动窗口:可以统计球员N 场的单刀成功率,更贴近状态。
  3. 引入xG:更专业地做"是否应进球"的评估,成功率可换成"相对 xG 的转化率"。
  4. 持久化数据:把 SingleShot 存到数据库(JPA/MyBatis),再做实时统计。

需要我进一步做成 Spring Boot + JPA 版本 或 带 Swing/JavaFX 界面的可视化版本 吗?

上一篇java案例复盘称这次伤病潮是否拖累球队?

下一篇当前分类已是最新一篇

抱歉,评论功能暂时关闭!