统计球员评分最高者 - Java案例
需求分析
给定一组球员数据(姓名、评分),找出评分最高的球员,如果有多个球员并列最高,全部输出。

完整代码实现
球员实体类
package com.example.player;
/**
* 球员实体类
*/
public class Player {
private String name; // 姓名
private String team; // 球队
private double score; // 评分
public Player(String name, String team, double score) {
this.name = name;
this.team = team;
this.score = score;
}
public String getName() {
return name;
}
public String getTeam() {
return team;
}
public double getScore() {
return score;
}
@Override
public String toString() {
return String.format("球员: %-10s 球队: %-8s 评分: %.1f", name, team, score);
}
}
主程序 - 三种实现方式
package com.example.player;
import java.util.*;
import java.util.stream.Collectors;
public class PlayerScoreDemo {
public static void main(String[] args) {
// 准备测试数据
List<Player> players = Arrays.asList(
new Player("梅西", "迈阿密国际", 8.9),
new Player("C罗", "利雅得胜利", 8.5),
new Player("姆巴佩", "皇马", 9.2),
new Player("哈兰德", "曼城", 8.7),
new Player("贝林厄姆", "皇马", 9.2),
new Player("维尼修斯", "皇马", 8.8)
);
System.out.println("========== 所有球员评分 ==========");
players.forEach(System.out::println);
System.out.println("\n========== 方式一:传统循环 ==========");
List<Player> top1 = findTopPlayersByLoop(players);
printResult(top1);
System.out.println("\n========== 方式二:Collections.max ==========");
List<Player> top2 = findTopPlayersByCollections(players);
printResult(top2);
System.out.println("\n========== 方式三:Stream流(推荐)==========");
List<Player> top3 = findTopPlayersByStream(players);
printResult(top3);
}
/**
* 方式一:传统 for 循环
*/
public static List<Player> findTopPlayersByLoop(List<Player> players) {
if (players == null || players.isEmpty()) {
return Collections.emptyList();
}
double maxScore = Double.NEGATIVE_INFINITY;
List<Player> result = new ArrayList<>();
for (Player p : players) {
if (p.getScore() > maxScore) {
// 发现更高分,清空重来
maxScore = p.getScore();
result.clear();
result.add(p);
} else if (p.getScore() == maxScore) {
// 分数相同,追加
result.add(p);
}
}
return result;
}
/**
* 方式二:Collections.max 先取最大值,再筛选
*/
public static List<Player> findTopPlayersByCollections(List<Player> players) {
if (players == null || players.isEmpty()) {
return Collections.emptyList();
}
// 找到最大评分
Player maxPlayer = Collections.max(players, Comparator.comparingDouble(Player::getScore));
double maxScore = maxPlayer.getScore();
// 筛选所有等于最大评分的球员
return players.stream()
.filter(p -> p.getScore() == maxScore)
.collect(Collectors.toList());
}
/**
* 方式三:Stream 流(推荐,最简洁)
*/
public static List<Player> findTopPlayersByStream(List<Player> players) {
if (players == null || players.isEmpty()) {
return Collections.emptyList();
}
double maxScore = players.stream()
.mapToDouble(Player::getScore)
.max()
.orElse(0);
return players.stream()
.filter(p -> p.getScore() == maxScore)
.collect(Collectors.toList());
}
/**
* 打印结果
*/
private static void printResult(List<Player> tops) {
if (tops.isEmpty()) {
System.out.println("没有球员数据");
return;
}
System.out.println("最高评分:" + tops.get(0).getScore());
System.out.println("最高评分球员共 " + tops.size() + " 名:");
tops.forEach(p -> System.out.println(" → " + p));
}
}
运行结果
========== 所有球员评分 ==========
球员: 梅西 球队: 迈阿密国际 评分: 8.9
球员: C罗 球队: 利雅得胜利 评分: 8.5
球员: 姆巴佩 球队: 皇马 评分: 9.2
球员: 哈兰德 球队: 曼城 评分: 8.7
球员: 贝林厄姆 球队: 皇马 评分: 9.2
球员: 维尼修斯 球队: 皇马 评分: 8.8
========== 方式一:传统循环 ==========
最高评分:9.2
最高评分球员共 2 名:
→ 球员: 姆巴佩 球队: 皇马 评分: 9.2
→ 球员: 贝林厄姆 球队: 皇马 评分: 9.2
========== 方式二:Collections.max ==========
最高评分:9.2
最高评分球员共 2 名:
→ 球员: 姆巴佩 球队: 皇马 评分: 9.2
→ 球员: 贝林厄姆 球队: 皇马 评分: 9.2
========== 方式三:Stream流(推荐)==========
最高评分:9.2
最高评分球员共 2 名:
→ 球员: 姆巴佩 球队: 皇马 评分: 9.2
→ 球员: 贝林厄姆 球队: 皇马 评分: 9.2
关键点说明
double 比较的坑 ⚠️
不要用 直接比较浮点数,因为存在精度问题(1 + 0.2 != 0.3)。
如果评分是精确到 0.1、0.01 的字符串或整数,建议:
// 方案A:评分扩大100倍转 int 存储(最推荐)
private int scoreTimes100;
// 方案B:使用 BigDecimal
private BigDecimal score;
// 方案C:比较时用误差容忍
if (Math.abs(p.getScore() - maxScore) < 1e-9) { ... }
本案例为了演示简洁,直接假设评分来源已知、精度损失在可接受范围内。
处理"并列第一"的重要性
要求"评分最高者是谁",若有并列,应全部返回,而不是只返回第一个。三种方式都实现了这个逻辑。
空集合的处理
findTopPlayersByStream 中用了 orElse(0),也可以改成返回 Optional:
OptionalDouble max = players.stream().mapToDouble(Player::getScore).max(); if (!max.isPresent()) return Collections.emptyList();
三种方式对比
| 方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| for 循环 | 只需遍历一次,性能最好 | 代码较长 | 数据量大、性能敏感 |
| Collections.max | 简洁语义化 | 需要遍历两次 | 中小规模数据 |
| Stream 流 | 最简洁、可读性强 | 需要遍历两次 | 推荐日常使用 |
进阶:按球队分组后取每组最高
如果需求变成"统计每支球队评分最高的球员":
Map<String, List<Player>> topByTeam = players.stream()
.collect(Collectors.groupingBy(
Player::getTeam,
Collectors.collectingAndThen(
Collectors.toList(),
list -> {
double max = list.stream()
.mapToDouble(Player::getScore).max().orElse(0);
return list.stream()
.filter(p -> p.getScore() == max)
.collect(Collectors.toList());
}
)
));
topByTeam.forEach((team, list) -> {
System.out.println("【" + team + "】评分最高:");
list.forEach(System.out::println);
});
输出:
【迈阿密国际】评分最高:
球员: 梅西 球队: 迈阿密国际 评分: 8.9
【利雅得胜利】评分最高:
球员: C罗 球队: 利雅得胜利 评分: 8.5
【皇马】评分最高:
球员: 姆巴佩 球队: 皇马 评分: 9.2
球员: 贝林厄姆 球队: 皇马 评分: 9.2
【曼城】评分最高:
球员: 哈兰德 球队: 曼城 评分: 8.7
这样一份完整的"球员评分最高者统计"案例就搞定了,涵盖了实体设计、三种算法实现和并发场景扩展。