我有以下代码
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答案
final List<String> list = map.values().stream().map(loc -> loc.getId()).collect(Collectors.toList());
java6中有什么要注意的地方吗?
不确定效率(因为它影响不大),但是如果您想使用lambda做到这一点,它可能像这样:
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);
编辑:该问题已修改,现在似乎不再涉及效率。现在,这个答案真的不再合适了,但是现在,我将其留在这里,也许有人觉得它很有帮助
首先是一般性提示:您说过
当我打印列表时,结果是a,b,c(按预期)。
但是,您应该不是期望如此。 HashMap
不会以任何方式排序。元素的顺序可以不同。同样重要的是:如果在地图中添加了[[more元素,则地图中先前包含的元素的顺序可能是change!
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
中的插入和删除稍微贵一点,但是这些性能差异在大多数情况下可以忽略不计。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(Lists.mutable.with("a", "b", "c"), list);
Assert.assertEquals(Bags.mutable.with("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(Lists.mutable.with("a", "b", "c"), list); Assert.assertEquals(Bags.mutable.with("a", "b", "c"), bag);
注意:我是Eclipse集合的提交者
Function
接口:Function
并像这样使用它:
public class ExtractLocationId implements Function<Location, String> { @Override public String apply(final Location location) { return location.getId(); } }
[它需要比Java 8 Lambda版本更多的代码(由于自己的final List<String> list =
FluentIterable.from(map.values()).transform(new ExtractLocationId()).toList();
实现,但它支持较旧的Java版本。