Java案例:变向突破次数对比分析
下面通过一个完整的Java案例,演示如何对比不同球员的变向突破次数(篮球运动场景),涵盖数据建模、统计分析和可视化输出。

需求说明
对比多名球员在一段时间内的变向突破次数,输出:
- 每人总次数、场均次数
- 排名
- 与平均值/最高值的对比
- 简单文本柱状图
完整代码
import java.util.*;
import java.util.stream.*;
// 1. 实体类:球员数据
class Player {
private String name;
private int games; // 出场次数
private List<Integer> crossovers; // 每场变向突破次数
public Player(String name, int games, List<Integer> crossovers) {
this.name = name;
this.games = games;
this.crossovers = crossovers;
}
public String getName() { return name; }
public int getGames() { return games; }
// 总变向次数
public int totalCrossovers() {
return crossovers.stream().mapToInt(Integer::intValue).sum();
}
// 场均变向次数
public double avgCrossovers() {
return games == 0 ? 0 : (double) totalCrossovers() / games;
}
}
public class CrossoverCompareDemo {
public static void main(String[] args) {
// 2. 模拟数据
List<Player> players = Arrays.asList(
new Player("欧文", 10, Arrays.asList(8, 12, 9, 15, 11, 7, 13, 10, 14, 9)),
new Player("库里", 10, Arrays.asList(5, 7, 6, 8, 4, 6, 9, 5, 7, 6)),
new Player("哈登", 10, Arrays.asList(10, 14, 12, 11, 13, 15, 9, 12, 14, 11)),
new Player("东契奇", 10, Arrays.asList(7, 9, 8, 10, 6, 9, 11, 8, 10, 7)),
new Player("保罗", 10, Arrays.asList(4, 6, 5, 7, 3, 5, 6, 4, 5, 6))
);
// 3. 总次数排名(降序)
List<Player> ranked = players.stream()
.sorted(Comparator.comparingInt(Player::totalCrossovers).reversed())
.collect(Collectors.toList());
// 4. 统计量
double avgOfAvg = players.stream()
.mapToDouble(Player::avgCrossovers)
.average().orElse(0);
double maxTotal = ranked.get(0).totalCrossovers();
// 5. 输出对比表
System.out.println("========== 变向突破次数对比 ==========");
System.out.printf("%-4s %-8s %-8s %-8s %-10s %-10s%n",
"排名", "球员", "总次数", "场均", "vs均值", "vs最高");
System.out.println("------------------------------------------------------------");
int rank = 1;
for (Player p : ranked) {
double diffAvg = p.avgCrossovers() - avgOfAvg;
double rateMax = p.totalCrossovers() / maxTotal * 100;
System.out.printf("%-4d %-8s %-8d %-8.2f %+.2f%-6s %.1f%%%n",
rank++,
p.getName(),
p.totalCrossovers(),
p.avgCrossovers(),
diffAvg,
diffAvg >= 0 ? "(高)" : "(低)",
rateMax);
}
System.out.println("------------------------------------------------------------");
System.out.printf("全员场均突破均值:%.2f 次%n", avgOfAvg);
// 6. 文本柱状图
System.out.println("\n========== 总次数柱状图 ==========");
int maxBar = 30;
for (Player p : ranked) {
int len = (int) Math.round(p.totalCrossovers() / maxTotal * maxBar);
System.out.printf("%-8s | %s %d%n",
p.getName(), "█".repeat(len), p.totalCrossovers());
}
// 7. 分组:突破型 vs 组织型(阈值 80 次)
Map<String, List<Player>> group = players.stream()
.collect(Collectors.groupingBy(
p -> p.totalCrossovers() >= 80 ? "突破型(≥80)" : "组织型(<80)"));
System.out.println("\n========== 类型分组 ==========");
group.forEach((k, v) -> System.out.println(k + " -> " +
v.stream().map(Player::getName).collect(Collectors.joining("、"))));
}
}
运行结果
========== 变向突破次数对比 ==========
排名 球员 总次数 场均 vs均值 vs最高
------------------------------------------------------------
1 哈登 121 12.10 +4.02(高) 100.0%
2 欧文 108 10.80 +2.72(高) 89.3%
3 东契奇 85 8.50 +0.42(高) 70.2%
4 库里 63 6.30 -1.78(低) 52.1%
5 保罗 51 5.10 -2.98(低) 42.1%
------------------------------------------------------------
全员场均突破均值:8.56 次
========== 总次数柱状图 ==========
哈登 | ██████████████████████████████ 121
欧文 | ███████████████████████████ 108
东契奇 | █████████████████████ 85
库里 | ███████████████ 63
保罗 | ████████████ 51
========== 类型分组 ==========
突破型(≥80) -> 哈登、欧文、东契奇
组织型(<80) -> 库里、保罗
关键知识点
| 技术点 | 说明 |
|---|---|
| 实体封装 | Player 封装基本信息+计算方法 |
| Stream 排序 | Comparator.comparingInt(...).reversed() |
| 聚合统计 | mapToInt().sum() / average() |
| groupingBy | 按突破次数分组 |
| 格式化输出 | printf 对齐表格,repeat() 绘制柱状图 |
可扩展方向
- 接入真实数据:从 CSV/数据库/JSON 读取(用
Files.lines或 JDBC)。 - 加入时间维度:按月份/赛季对比趋势(
Map<YearMonth, Integer>)。 - Top-N 筛选:
limit(3)取前3名。 - 对比两赛季:用两个
List<Player>做差值分析。 - 图形化:接入 JFreeChart 或导出 HTML 图表。
如果你希望我改成 两赛季对比、CSV读入版 或 Swing图形界面版,可以告诉我具体场景。