Java8从映射中匹配的值中提取第一个键
假设我有一个给定名称、姓氏对的映射,我想找到该映射中第一个条目的给定名称,该条目的姓氏与某个值匹配。 我们将如何以Java8的方式实现这一点 在下面的测试用例示例中,我提出了两种方法 但是,第一个(查找第一个姓氏为“驴子”的人的名字)将抛出java.util.NoSuchElementException:不存在值,因此不安全 第二个很好用,但它不仅很难阅读,而且有点不太实用 我只是想知道这里是否有人会建议我使用Java8从映射中匹配的值中提取第一个键,java,lambda,java-8,java-stream,optional,Java,Lambda,Java 8,Java Stream,Optional,假设我有一个给定名称、姓氏对的映射,我想找到该映射中第一个条目的给定名称,该条目的姓氏与某个值匹配。 我们将如何以Java8的方式实现这一点 在下面的测试用例示例中,我提出了两种方法 但是,第一个(查找第一个姓氏为“驴子”的人的名字)将抛出java.util.NoSuchElementException:不存在值,因此不安全 第二个很好用,但它不仅很难阅读,而且有点不太实用 我只是想知道这里是否有人会建议我使用stream()或forEach()或两者都可以更简单更清晰地实现这一点 @Test
stream()
或forEach()
或两者都可以更简单更清晰地实现这一点
@Test
public void shouldBeAbleToReturnTheKeyOfTheFirstMatchingValue() throws Exception {
Map<String, String> names = new LinkedHashMap<>();
names.put("John", "Doe");
names.put("Fred", "Flintstone");
names.put("Jane", "Doe");
String keyOfTheFirst = names.entrySet().stream().filter(e -> e.getValue().equals("Doe")).findFirst().get().getKey();
assertEquals("John", keyOfTheFirst);
try {
names.entrySet().stream().filter(e -> e.getValue().equals("Donkey")).findFirst().get();
} catch (NoSuchElementException e){
// Expected
}
Optional<Map.Entry<String, String>> optionalEntry = names.entrySet().stream().filter(e -> e.getValue().equals("Donkey")).findFirst();
keyOfTheFirst = optionalEntry.isPresent() ? optionalEntry.get().getKey() : null;
assertNull(keyOfTheFirst);
}
@测试
public void应该能够返回FirstMatching Value()的键引发异常{
映射名称=新LinkedHashMap();
姓名。填写(“约翰”、“多伊”);
姓名。填写(“弗雷德”、“弗林斯通”);
姓名。填写(“Jane”、“Doe”);
字符串keyOfFirst=names.entrySet().stream().filter(e->e.getValue().equals(“Doe”).findFirst().get().getKey();
assertEquals(“约翰”,第一位的钥匙);
试一试{
name.entrySet().stream().filter(e->e.getValue().equals(“驴”)).findFirst().get();
}捕获(无接触元素例外e){
//期望
}
可选optionalEntry=names.entrySet().stream().filter(e->e.getValue().equals(“驴”)).findFirst();
KeyOfFirst=optionalEntry.isPresent()?optionalEntry.get().getKey():null;
assertNull(KeyofFirst);
}
提前感谢您。来自类似网站:
我喜欢老式的:
static <K, V> K findFirstKeyByValue(Map<K, V> map, String value) {
for (Entry<K, V> e : map.entrySet())
if (e.getValue().equals(value))
return e.getKey();
return null;
}
静态K findFirstKeyByValue(映射映射,字符串值){
对于(条目e:map.entrySet())
如果(如getValue().equals(value))
返回e.getKey();
返回null;
}
要在不匹配时返回默认值,请使用
如果您不想使用第三方代码,@Misha提供的解决方案是最好的。对于我发现这是一项非常常见的任务的情况,具有特殊的快捷方式:
StreamEx.ofKeys(names, "Donkey"::equals).findFirst().orElse(null);
下面是我从映射中获取密钥的代码片段
Map<String,String> pageDetails = new HashMap<String,String>();
public String getAssociatedKey(){
pageDetails.entrySet().stream().filter( e -> e.getValue().contains("John").findFirst().get().getKey();
}
Map pageDetails=newhashmap();
公共字符串getAssociatedKey(){
pageDetails.entrySet().stream().filter(e->e.getValue().contains(“John”).findFirst().get().getKey();
}
为了避免映射条目存在空值时出现空指针异常:
private String getValueByKey(Map<String, String> map, String key)
{
return map.entrySet().stream().filter(e ->
StringUtils.equalsIgnoreCase(e.getKey(), key)).findFirst().get()
.getValue();
}
私有字符串getValueByKey(映射映射,字符串键)
{
返回map.entrySet().stream().filter(e->
StringUtils.equalsIgnoreCase(e.getKey(),key)).findFirst().get()
.getValue();
}
而不是collect
您可以使用findAny
来获取找到的第一个。@PeterLawrey提醒得很好!但它将是findFirst
,不是吗?除非您使用并行流,否则它将是第一个。但这与我的第二个解决方案类似。您仍然需要迭代到收集的集或检查选项是否正确findFirst返回的所有值都存在,以便获得实际的密钥。我正在寻找lambda中发生的事情,如果有,它将返回我想要的密钥,否则将返回空值。@Julian,恐怕您不能再进一步了。您不能保证始终能找到密钥。显然,使用双向映射将更有效。您好patryk.我完全同意你的看法。这就是我发布这个问题的原因。你能提供一个解决方案吗?对我来说,一些气味来自于使用null
。发布的答案都提供了null
,因为这是你要求的。但是既然你买了可选的,为什么要使用null
keyoffirst
beOptional
和doassertTrue(keyoffirst.isEmpty())
或任何东西。@Stuart.当然,使用java.util.Optional
是自然的方式,但这不是我想要的。我真正想要的是一个纯函数式的解决方案,而不需要任何额外的检查/迭代等。这更像是一个理论问题“java 8能做到吗?”因为我自己找不到答案,所以我把它贴在这里,而不是得出结论说找不到。单元测试只是为了帮助海报轻松地运用他们的解决方案,而不是别的。@Julian Fair。我对上面的评论做出了回应,“这段代码很臭。设计很差。”这个评论可能是真的,但并不是特别有用。虽然它与您所关注的问题没有直接关系,但我确实意识到代码的一个问题是它使用了null
,因此我建议了一个避免null
。谢谢Misha和Doon。您的两个回答都帮助我找到了我想要的解决方案。我我选择Misha作为最接近它的。要返回java.lang.String
而不是java.util.Optional
我所要做的就是调用orElseGet(new Supplier(){@Override public String get(){return null;})
如果确实希望使用orElseGet
而不是orElse
,则可以使用lambda表达式而不是匿名类:.orElseGet(()->null)
。谢谢Misha。这更好,也正是我想要的:这个问题的纯函数解决方案。Java 8 rocks!使用,它将是PairStream.from(names).filterValue(“驴子”::equals).keys().findFirst()
。在某些情况下,.orElse(null)
可以更改为.orElseGet(()->Iterables.getLast(yourCollection))
这不会过滤名为驴的键,而不是对应名为驴的值的键吗?@flup,不会,这是对对应名为“驴”
的值的键的过滤。要过滤键,可以使用常用的过滤方法,如StreamEx.ofKeys(names).filter(“驴”::equals)
。
StreamEx.ofKeys(names, "Donkey"::equals).findFirst().orElse(null);
Map<String,String> pageDetails = new HashMap<String,String>();
public String getAssociatedKey(){
pageDetails.entrySet().stream().filter( e -> e.getValue().contains("John").findFirst().get().getKey();
}
private String getValueByKey(Map<String, String> map, String key)
{
return map.entrySet().stream().filter(e ->
StringUtils.equalsIgnoreCase(e.getKey(), key)).findFirst().get()
.getValue();
}