Java 有没有更好的方法从映射中检索值
我有以下代码Java 有没有更好的方法从映射中检索值,java,collections,lambda,guava,Java,Collections,Lambda,Guava,我有以下代码 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 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());
}
在Java6中,有没有更好的方法不使用for循环来获取Id
根据Java8,引用代码形式@rohit jain answer
final List<String> list = map.values().stream().map(loc -> loc.getId()).collect(Collectors.toList());
final List List=map.values().stream().map(loc->loc.getId()).collect(Collectors.toList());
在java6中有这样的考虑吗?在某一点上,您不能逃避映射上的迭代。 对于映射,最有效的方法是迭代“entrySet()”不确定效率(因为它不会影响太多),但如果您想使用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
final List<String> list =
FluentIterable.from(map.values()).transform(new ExtractLocationId()).toList();
编辑:该问题已被修改,现在似乎不再涉及效率。现在,这个答案已经不合适了,但现在,我把它留在这里,也许有人会觉得它有用
首先是一个一般性的提示:你说
当我打印列表时,结果是a、b、c(如预期)
for (final String string : list) {
System.out.println(string);
}
然而,你应该而不是期望那样。HashMap没有以任何方式排序。elments的顺序可能会有所不同。同样重要的是:如果您在地图中添加了更多元素,那么先前包含在地图中的元素的顺序可能会改变
如果希望迭代期间元素的顺序与插入顺序相同,则应使用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;
}
}
同样,这不应该被认为是理所当然的,除非它通过一个合适的Micobenchmarking框架进行验证,但坦率地说:LinkedHashMap
速度快了30%,要么给,要么拿,我怀疑Micobenchmarking框架会告诉我相反的情况
一般来说,我基本上总是使用
LinkedHashMap
而不是普通的HashMap
。但不是因为性能,而是主要因为一致的迭代顺序。关于性能:在LinkedHashMap
中的插入和删除可能比HashMap
要贵一点,但在大多数情况下,这些性能差异可以忽略不计。如果您喜欢使用兼容Java 6的版本,那么您可以使用Guava及其接口:
public class ExtractLocationId implements Function<Location, String> {
@Override
public String apply(final Location location) {
return location.getId();
}
}
公共类ExtractLocationId实现函数{
@凌驾
公共字符串应用(最终位置){
返回location.getId();
}
}
然后像这样使用它:
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
final List<String> list =
FluentIterable.from(map.values()).transform(new ExtractLocationId()).toList();
最终列表=
FluentIterable.from(map.values()).transform(new-ExtractLocationId()).toList();
它需要比Java 8 Lambda版本更多的代码(由于它自己的函数
实现),但它支持较旧的Java版本。如果使用,可以编写以下代码:
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);
MutableMap=Maps.mutable.empty();
地图放置(“1”,新位置(“a”,空));
地图放置(“2”,新位置(“b”,空));
地图放置(“3”,新位置(“c”,空));
List=map.collect(位置::getId.toSortedList();
Bag Bag=地图收集(位置::getId);
Assert.assertEquals(list.mutable.with(“a”、“b”、“c”),list);
Assert.assertEquals(Bags.mutable.with(“a”、“b”、“c”),bag);
以下代码也适用于Java5-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);
Function=new Function()
{
公共字符串值(位置)
{
返回location.getId();
}
};
List=map.collect(函数).toSortedList();
袋子=地图收集(功能);
Assert.assertEquals(list.mutable.with(“a”、“b”、“c”),list);
Assert.assertEquals(Bags.mutable.with(“a”、“b”、“c”),bag);
注意:我是Eclipse集合的提交人您能更具体地说一下您所说的高效吗?在某种程度上,如果要打印条目,您需要迭代映射中的条目。现在有办法解决这个问题。另外,请注意,结果很可能是c、a、b或b、a、c或任何其他组合。为了澄清,效率意味着我可以去掉第一个For循环。我知道我需要打印第二张,这是不可避免的。不。没有更好的方法了。
for(最终位置s:map.values()){System.out.println(s.getId());}
。如果您只想打印值,则无需创建临时列表。如果OP不关心键,为什么迭代entrySet比迭代值更有效?由于整体性能,迭代映射项的速度比迭代键或值更快。@Dae您能证明这一点吗?我的意思是,当谈到效率时,我不相信任何文字。@Dae你应该阅读源代码。您会发现,值上的迭代器与条目上的迭代器相同,只是它返回的是值而不是条目。您以秒赢得了我!;)也许终端操作可以是forEach(System.out::println)。这样,当OP请求时,只会发生1次。@Magnamag补充说:)打印是次要的,我知道即使使用lambdas,也会发生至少1次值传递,我的问题是,我能否像在java8中那样在java6中更简洁地编写此代码。如果问题是这样,我道歉misleading@SDS在Java6中,没有。这是您将获得的最好结果。