Java 对流使用hashmap时的索引
我有一个团队的散列图需要打印出来。它们需要通过一些参数(不相关)进行索引和排序。除了索引部分,其他一切都很好,我在某种程度上得到了工作,但感觉不对劲Java 对流使用hashmap时的索引,java,indexing,hashmap,java-stream,Java,Indexing,Hashmap,Java Stream,我有一个团队的散列图需要打印出来。它们需要通过一些参数(不相关)进行索引和排序。除了索引部分,其他一切都很好,我在某种程度上得到了工作,但感觉不对劲 int i=0; public void printTable() { StringBuilder sb = new StringBuilder(); i = 0; table.keySet().stream() .map(key -> table.get(key))
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获取对象。更新答案
应避免使用有状态流/lambda表达式。由于这个原因,我下面的原始答案是个坏主意
更好的方法是将流和打印分开
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());
AtomicInteger
将在不更改引用/修改原语的情况下为您提供可变性。您不需要在映射中进行查找,您可以直接对值进行迭代
编辑
正如@Eugene在评论中指出的,如果您使用并行流,则不能使用带有
AtomicInteger
的方法。我会将排序与打印分开
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());
分类:
List<Team> sorted = table.values().stream()
.sorted(Comparator.comparing(Team::getPoints)
.thenComparing(Team::goalDifference)
.reversed()
.thenComparing(Team::getName))
.collect(Collectors.toList());
如果团队
类有一个接受位置并返回格式化字符串的方法,则可以改进这一点:
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"));
这是错误的。简化
Stream.of(“a”、“b”、“c”、“d”).map(x->i.incrementAndGet()+“-”+x).parallel().forEach(System.out::println)
一个可能的结果2-d
或1-c
是完全可能的,但是如果您知道并行流会失败,并且您反对它,您可以使用int[]
使用单个值而不是AtomicInteger
这一事实是一个实现细节,即它恰好可以通过顺序流执行所需的操作。无论这里的execution mode.OP是什么,都不能保证map
函数是按遭遇顺序计算的。我在另一个线程中看到,使用并行流会给我错误的结果,而使用AtomicInteger目前还可以,因为我不需要执行并行流。你的和@federico对我来说都很好,我选择你的是因为它更简单。只是关于另一种方法的附带问题。我知道ArrayList的get方法的复杂度为O(1),LinkedList的复杂度为O(n)。列表的获取方法复杂度是多少?如果不是O(1),那么这种方法就没有意义了,因为我们在列表中循环了n*n次。没关系。为了回答我自己的问题,在另一个线程中,我看到当我们执行.collect(Collectors.toList())
时,“对于返回的列表的类型、可变性、序列化性或线程安全性没有保证”。为了得到我们想要的实现,我们可以执行.collect(collector.toCollection(()->new ArrayList())
String table = IntStream.range(0, sorted.size())
.mapToObj(Team::formatWithPosition)
.collect(Collectors.joining("\n"));