Java 案例:赛季累计数据统计与对比
下面给你一个完整可运行的 Java 案例,模拟 NBA/CBA 球员赛季数据统计并做对比(得分、篮板、助攻、命中率等),包含排序、对比、Top 榜单等常见需求。

需求场景
- 输入:一批球员的赛季累计数据
- 输出:
- 每个球员的场均数据
- 按得分排序的榜单
- 任意两名球员的数据对比
- 找出各项数据的"联盟第一"
核心代码
实体类 PlayerStats
import java.util.Objects;
public class PlayerStats {
private String name; // 球员姓名
private String team; // 球队
private int games; // 出场数
private int points; // 总得分
private int rebounds; // 总篮板
private int assists; // 总助攻
private int steals; // 总抢断
private int blocks; // 总盖帽
private int fga; // 出手数
private int fgm; // 命中数
public PlayerStats(String name, String team, int games,
int points, int rebounds, int assists,
int steals, int blocks, int fga, int fgm) {
this.name = name;
this.team = team;
this.games = games;
this.points = points;
this.rebounds = rebounds;
this.assists = assists;
this.steals = steals;
this.blocks = blocks;
this.fga = fga;
this.fgm = fgm;
}
// 场均数据
public double ppg() { return games == 0 ? 0 : (double) points / games; }
public double rpg() { return games == 0 ? 0 : (double) rebounds / games; }
public double apg() { return games == 0 ? 0 : (double) assists / games; }
public double spg() { return games == 0 ? 0 : (double) steals / games; }
public double bpg() { return games == 0 ? 0 : (double) blocks / games; }
public double fgPct() { return fga == 0 ? 0 : (double) fgm / fga; }
// getters
public String getName() { return name; }
public String getTeam() { return team; }
public int getGames() { return games; }
public int getPoints() { return points; }
public int getRebounds(){ return rebounds; }
public int getAssists() { return assists; }
@Override
public String toString() {
return String.format("%-8s %-6s 出场%2d | 场均 %.1f分 %.1f板 %.1f助 | 命中率 %.1f%%",
name, team, games, ppg(), rpg(), apg(), fgPct() * 100);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PlayerStats)) return false;
PlayerStats that = (PlayerStats) o;
return Objects.equals(name, that.name) && Objects.equals(team, that.team);
}
@Override
public int hashCode() {
return Objects.hash(name, team);
}
}
主程序 SeasonStatsDemo
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class SeasonStatsDemo {
public static void main(String[] args) {
List<PlayerStats> players = initData();
System.out.println("==================== 赛季累计数据总览 ====================");
players.forEach(System.out::println);
System.out.println("\n==================== 场均得分 Top 5 ====================");
rankBy(players, PlayerStats::ppg, 5, "得分");
System.out.println("\n==================== 场均篮板 Top 3 ====================");
rankBy(players, PlayerStats::rpg, 3, "篮板");
System.out.println("\n==================== 场均助攻 Top 3 ====================");
rankBy(players, PlayerStats::apg, 3, "助攻");
System.out.println("\n==================== 联盟第一(得分王/篮板王/助攻王) ====================");
findKing(players, PlayerStats::ppg, "得分王");
findKing(players, PlayerStats::rpg, "篮板王");
findKing(players, PlayerStats::apg, "助攻王");
System.out.println("\n==================== 球员一对一对比 ====================");
compare(players, "张三", "李四");
System.out.println("\n==================== 按球队分组统计 ====================");
groupByTeam(players);
}
/** 初始化模拟数据 */
private static List<PlayerStats> initData() {
return new ArrayList<>(List.of(
new PlayerStats("张三", "湖人", 60, 1560, 420, 480, 90, 40, 1100, 520),
new PlayerStats("李四", "勇士", 58, 1420, 350, 520, 75, 30, 1050, 460),
new PlayerStats("王五", "雄鹿", 62, 1700, 610, 320, 60, 80, 1200, 600),
new PlayerStats("赵六", "凯尔特", 55, 1100, 480, 260, 45, 55, 950, 400),
new PlayerStats("孙七", "掘金", 65, 1300, 700, 400, 50, 70, 1000, 480),
new PlayerStats("周八", "太阳", 50, 900, 300, 380, 40, 20, 800, 320)
));
}
/** 通用排序 - 按某个场均字段倒序输出 Top N */
private static void rankBy(List<PlayerStats> players,
Function<PlayerStats, Double> keyExtractor,
int topN, String label) {
players.stream()
.sorted(Comparator.comparingDouble((PlayerStats p) -> keyExtractor.apply(p)).reversed())
.limit(topN)
.forEach(p -> System.out.printf("%-6s | 场均%s = %.2f%n",
p.getName(), label, keyExtractor.apply(p)));
}
/** 找出某数据项的第一名 */
private static void findKing(List<PlayerStats> players,
Function<PlayerStats, Double> keyExtractor,
String title) {
players.stream()
.max(Comparator.comparingDouble((PlayerStats p) -> keyExtractor.apply(p)))
.ifPresent(p -> System.out.printf("【%s】%s(%s) %.2f%n",
title, p.getName(), p.getTeam(), keyExtractor.apply(p)));
}
/** 两名球员数据对比 */
private static void compare(List<PlayerStats> players, String n1, String n2) {
PlayerStats p1 = players.stream().filter(p -> p.getName().equals(n1)).findFirst().orElse(null);
PlayerStats p2 = players.stream().filter(p -> p.getName().equals(n2)).findFirst().orElse(null);
if (p1 == null || p2 == null) {
System.out.println("未找到指定球员");
return;
}
printCompareRow("场均得分", p1.ppg(), p2.ppg());
printCompareRow("场均篮板", p1.rpg(), p2.rpg());
printCompareRow("场均助攻", p1.apg(), p2.apg());
printCompareRow("命中率", p1.fgPct() * 100, p2.fgPct() * 100);
}
private static void printCompareRow(String label, double v1, double v2) {
String flag = v1 > v2 ? "← 占优" : (v1 < v2 ? "→ 占优" : "持平");
System.out.printf("%-8s 张三: %6.2f 李四: %6.2f %s%n", label, v1, v2, flag);
}
/** 按球队分组,计算每组平均得分 */
private static void groupByTeam(List<PlayerStats> players) {
Map<String, Double> avgPointsByTeam = players.stream()
.collect(Collectors.groupingBy(
PlayerStats::getTeam,
Collectors.averagingDouble(PlayerStats::ppg)));
avgPointsByTeam.forEach((team, avg) ->
System.out.printf("%-8s 平均得分:%.2f%n", team, avg));
}
}
运行输出示例
==================== 赛季累计数据总览 ====================
张三 湖人 出场60 | 场均 26.0分 7.0板 8.0助 | 命中率 47.3%
李四 勇士 出场58 | 场均 24.5分 6.0板 9.0助 | 命中率 43.8%
王五 雄鹿 出场62 | 场均 27.4分 9.8板 5.2助 | 命中率 50.0%
...
==================== 场均得分 Top 5 ====================
王五 | 场均得分 = 27.42
张三 | 场均得分 = 26.00
李四 | 场均得分 = 24.48
...
==================== 联盟第一(得分王/篮板王/助攻王) ====================
【得分王】王五(雄鹿) 27.42
【篮板王】孙七(掘金) 10.77
【助攻王】李四(勇士) 8.97
==================== 球员一对一对比 ====================
场均得分 张三: 26.00 李四: 24.48 ← 占优
场均篮板 张三: 7.00 李四: 6.03 ← 占优
场均助攻 张三: 8.00 李四: 8.97 → 占优
命中率 张三: 47.27 李四: 43.81 ← 占优
==================== 按球队分组统计 ====================
湖人 平均得分:26.00
勇士 平均得分:24.48
...
关键技术点解析
| 需求 | 用法 |
|---|---|
| 场均数据 | 类中封装 ppg()、rpg() 等方法 |
| 排序 | Comparator.comparingDouble(...).reversed() |
| Top N | sorted().limit(N) |
| 找最大 | stream().max(...) |
| 分组聚合 | Collectors.groupingBy + averagingDouble |
| 通用字段提取 | Function<PlayerStats, Double> 函数式接口 |
| 一对一对比 | 用 ifPresent / Optional 安全取值 |
可扩展方向
- 接入真实数据:从 CSV / JSON 文件读取 → 用
BufferedReader或 Jackson 解析。 - 进阶指标:真实命中率 TS%、效率值 PER、正负值 ±。
- 导出报告:用
POI导出 Excel,或生成 HTML 报告。 - 多赛季对比:加一个
season字段,用groupingBy(PlayerStats::getSeason)分组。 - GUI/Web 化:改用 Spring Boot 提供 REST 接口,前端 ECharts 可视化。
如果你告诉我具体场景(比如学生成绩、销售业绩、游戏战绩),我可以把字段和指标换成你的业务场景,给你一版更贴合的代码。