我有以下代码
final Map<String, Location> map = new HashMap<>();
map.put("1", new Location("a", null));
map.put("2", new Location("b", null));
map.put("3", new Location("c", null));
final List<String> list = new ArrayList<>();
for (final Location s : map.values()) {
list.add(s.getId());
}
当我打印列表时,结果是a,b,c(如预期的那样)。
for (final String string : list) {
System.out.println(string);
}
有没有更好的方法来获取Id而不使用 Java6 中的for循环。
根据Java8,引用代码形式@ rohit-jain answer
final List<String> list = map.values().stream().map(loc -> loc.getId()).collect(Collectors.toList());
java6中有什么这个构思吗?
答案 0 :(得分:3)
不确定效率(因为它不会影响太多),但如果你想使用lambdas这样做,它可以是这样的:
final Map<String, Location> locationMap = new HashMap<>();
locationMap.put("1", new Location("a", null));
locationMap.put("2", new Location("b", null));
locationMap.put("3", new Location("c", null));
final List<String> list = locationMap.values().stream()
.map(loc -> loc.getId())
.collect(Collectors.toList());
System.out.println(list); // can be `[a, b, c]` or `[b, c, a]`, etc
但是,仅仅因为你在这里看不到for
循环并不意味着它不会迭代地图的值。它确实如此,但只是隐藏了迭代逻辑。
或者,如果您只想打印该值(一次使用),您甚至可以避免在那里创建列表:
locationMap.values().stream().map(loc -> loc.getId())
.forEach(System.out::println);
答案 1 :(得分:3)
编辑:问题被修改了,现在似乎不再提及效率了。现在,这个答案不再适用了,但就目前而言,我会把它留在这里,也许有人觉得它很有帮助
首先提出一般性提示:你说
当我打印列表时,结果是a,b,c(如预期的那样)。
但是,你应该不期望。 HashMap
未按任何方式排序。元素的顺序可能不同。同样重要的是:如果您将更多元素添加到地图中,那么先前包含在地图中的元素的顺序可以更改!
如果您希望迭代期间元素的顺序与插入顺序相同,则应使用LinkedHashMap
而不是HashMap
。它保留了迭代顺序,在那里,您对输出的期望将得到满足。
有趣的是,这导致了关于性能的问题:
实际上迭代LinkedHashMap
可能(显着)比迭代Map
更快。这是一个小的微型基准标记,一如既往地应该用一粒盐:
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;
public class MapIteration
{
public static void main(String[] args)
{
long sum = 0;
for (int size=100000; size<=1000000; size += 100000)
{
Map<String, Integer> mapA =
new HashMap<String, Integer>();
fillMap(mapA, size);
Map<String, Integer> mapB =
new LinkedHashMap<String, Integer>();
fillMap(mapB, size);
int runs = 100;
long beforeA = System.nanoTime();
for (int i=0; i<runs; i++)
{
sum += computeValueSum(mapA);
}
long afterA = System.nanoTime();
double durationA = (afterA - beforeA) / 1e6;
long beforeB = System.nanoTime();
for (int i=0; i<runs; i++)
{
sum += computeValueSum(mapB);
}
long afterB = System.nanoTime();
double durationB = (afterB - beforeB) / 1e6;
System.out.printf(
"Normal size %10d duration %10.3f\n", size, durationA);
System.out.printf(
"Linked size %10d duration %10.3f\n", size, durationB);
}
System.out.println(sum);
}
private static void fillMap(Map<String, Integer> map, int n)
{
Random random = new Random(0);
for (int i=0; i<n; i++)
{
map.put(String.valueOf(i), random.nextInt(n));
}
}
private static long computeValueSum(Map<?, Integer> map)
{
long sum = 0;
for (Integer i : map.values())
{
sum += i;
}
return sum;
}
}
对我来说,打印......
...
Normal size 1000000 duration 2611,288
Linked size 1000000 duration 1796,030
同样,这不应该被视为理所当然,除非通过适当的Micobenchmarking框架进行验证,但坦率地说:LinkedHashMap
快30%,给予或采取一些,我怀疑是Micobenchmarking框架会告诉我相反的情况。
一般来说,我基本上总是使用LinkedHashMap
而不是普通HashMap
。但不是因为性能,而主要是因为迭代顺序一致。关于性能:LinkedHashMap
中的插入和删除可能比HashMap
更贵,但在大多数情况下,这些性能差异可以忽略不计。
答案 2 :(得分:3)
如果您使用GS Collections,则可以写下以下内容:
MutableMap<String, Location> map = Maps.mutable.empty();
map.put("1", new Location("a", null));
map.put("2", new Location("b", null));
map.put("3", new Location("c", null));
List<String> list = map.collect(Location::getId).toSortedList();
Bag<String> bag = map.collect(Location::getId);
Assert.assertEquals(FastList.newListWith("a", "b", "c"), list);
Assert.assertEquals(HashBag.newBagWith("a", "b", "c"), bag);
以下代码也适用于Java 5 - 7:
Function<Location, String> function = new Function<Location, String>()
{
public String valueOf(Location location)
{
return location.getId();
}
};
List<String> list = map.collect(function).toSortedList();
Bag<String> bag = map.collect(function);
Assert.assertEquals(FastList.newListWith("a", "b", "c"), list);
Assert.assertEquals(HashBag.newBagWith("a", "b", "c"), bag);
注意:我是GS Collections的开发人员
答案 3 :(得分:2)
如果您想使用Java 6兼容版本,那么您可以使用Guava及其Function
界面:
public class ExtractLocationId implements Function<Location, String> {
@Override
public String apply(final Location location) {
return location.getId();
}
}
并像这样使用它:
final List<String> list =
FluentIterable.from(map.values()).transform(new ExtractLocationId()).toList();
它需要的代码多于Java 8 Lambda版本(由于自己的Function
实现),但它支持较旧的Java版本。
答案 4 :(得分:0)
你不能在某个时刻逃避地图上的迭代。 对于地图,最有效的方法是迭代&#34; entrySet()&#34;。