使用带有流

时间:2018-01-24 16:16:14

标签: java indexing hashmap java-stream

我有一个团队的HashMap,我需要打印出来。它们需要被索引并按一些参数排序(不相关)。一切正常,除了索引部分,我在某种程度上工作,但感觉不对。

int i=0;

public void printTable()
{
    StringBuilder sb = new StringBuilder();

    i = 0;

    table.keySet().stream()
                .map(key -> table.get(key))
                .sorted(Comparator.comparing(Team::getPoints).thenComparing(Team::goalDifference).reversed().thenComparing(Team::getName))
                .forEach(team -> sb.append(String.format("%2d%s %-15s%5d%5d%5d%5d%5d\n", ++i, ".", team.getName(), team.getPlayed(),
                         team.getWins(), team.getDraws(), team.getLosses(), team.getPoints())));

    System.out.print(sb.toString());
}

有更好的方法吗?我不认为Intstream会在这里提供帮助,因为我无法使用索引从HashMap中获取对象。

2 个答案:

答案 0 :(得分:2)

更新答案

您应该避免使用有状态的流/ lambda表达式。 reference。由于这个原因,我在下面的原始答案是一个坏主意。

更好的方法是将流和打印分开。

List<Team> teams = table.values()
        .stream()
        .sorted(...)
        .collect(Collectors.toList());

StringBuilder sb = new StringBuilder();
for(int i=0; i<teams.size(); i++) {

    Team team = teams.get(i);
    sb.append(String.format("%2d. %-15s%5d%5d%5d%5d%5d\n", 
            i,
            team.getName(),
            team.getPlayed(),
            team.getWins(),
            team.getDraws(),
            team.getLosses(), 
            team.getPoints()));
}

System.out.println(sb.toString());

原始答案[错误想法]

您无法修改在流或lambda中使用的变量/修改基元的引用。您可以像下面那样重写代码,

AtomicInteger i = new AtomicInteger();
String result = table.values()
        .stream()
        .sorted(...)
        .map(e -> i.incrementAndGet() + "_" + e)
        .collect(Collectors.joining());

AtomicInteger会在不更改引用/修改基元的情况下为您提供可变性。您不需要在地图中查找,您可以直接迭代值。

修改

正如@Eugene在评论中指出的那样,如果使用并行流,则无法使用AtomicInteger的方法。

答案 1 :(得分:2)

我会将分类与打印分开。

排序:

List<Team> sorted = table.values().stream()
    .sorted(Comparator.comparing(Team::getPoints)
            .thenComparing(Team::goalDifference)
            .reversed()
            .thenComparing(Team::getName))
    .collect(Collectors.toList());

印刷:

String table = IntStream.range(0, sorted.size())
    .mapToObj(i -> String.format("%2d%s %-15s%5d%5d%5d%5d%5d", 
            i, ".", 
            sorted.get(i).getName(), 
            sorted.get(i).getPlayed(),
            sorted.get(i).getWins(), 
            sorted.get(i).getDraws(), 
            sorted.get(i).getLosses(), 
            sorted.get(i).getPoints()))
    .collect(Collectors.joining("\n"));

如果Team类有一个接受位置并返回格式化字符串的方法,则可以改进:

public String formatWithPosition(int position) {
    return String.format("%2d%s %-15s%5d%5d%5d%5d%5d", 
            position, ".", 
            name, played, wins, draws, losses, points);
}

然后,您可以按如下方式使用它:

String table = IntStream.range(0, sorted.size())
    .mapToObj(Team::formatWithPosition)
    .collect(Collectors.joining("\n"));