Подтвердить что ты не робот

Java 8 извлекает первый ключ из значения соответствия на карте

Предположим, что у меня есть карта заданного имени, фамилии, и я хочу найти заданное имя первой записи на той карте, у которой есть фамилия, соответствующая определенному значению. Как мы будем делать это с использованием java 8.

В приведенном ниже примере тестового примера я делаю два способа сделать это.

Однако первый (ищет имя первого человека с фамилией "Осел" ) будет бросать java.util.NoSuchElementException: нет значения, чтобы оно было безопасным.

Второй работает, но читать его не только труднее, но и немного не совсем функционально.

Просто интересно, может ли кто-нибудь предложить мне более простой способ достичь этого, используя либо 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);
}

Спасибо заранее.

4b9b3361

Ответ 1

Чтобы вернуть значение по умолчанию, если нет совпадения, используйте Optional#orElse

names.entrySet().stream()
  .filter(e -> e.getValue().equals("Donkey"))
  .map(Map.Entry::getKey)
  .findFirst()
  .orElse(null);

Ответ 2

Решение, предоставляемое @Misha, является лучшим, если вы не хотите использовать сторонний код. Моя библиотека имеет специальный метод быстрого доступа ofKeys для таких когда я обнаружил, что это довольно общая задача:

StreamEx.ofKeys(names, "Donkey"::equals).findFirst().orElse(null);

Ответ 3

Из аналогичного вопроса :

public static <T, E> Set<T> getKeysByValue(Map<T, E> map, E value) {
    return map.entrySet()
              .stream()
              .filter(entry -> Objects.equals(entry.getValue(), value))
              .map(Map.Entry::getKey)
              .collect(Collectors.toSet());
}

Затем вы можете выбрать первый, если хотите. Помните, что key уникален, value не является.

Изменить: Весь код (спасибо @Peter Lawrey)

package test;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

public class Main {

    public static void main(String[] args) {
        Map<String, String> names = new LinkedHashMap<>();
        names.put("John", "Doe");
        names.put("Fred", "Flintstone");
        names.put("Jane", "Doe");

        Optional<String> firstKey = names.entrySet().stream()
                .filter(entry -> Objects.equals(entry.getValue(), "Doe"))
                .map(Map.Entry::getKey).findFirst();

        if (firstKey.isPresent()) {
            System.out.println(firstKey.get());
        }
    }
}

Ответ 4

Мне нравится старомодный:

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;
}

Ответ 5

Ниже приведен мой фрагмент кода, чтобы получить ключ от карты,

Map<String,String> pageDetails = new HashMap<String,String>();

public String getAssociatedKey(){
pageDetails.entrySet().stream().filter( e -> e.getValue().contains("John").findFirst().get().getKey();
}

Ответ 6

Чтобы избежать исключения нулевого указателя, если запись карты существует с нулевым значением:

private String getValueByKey (Карта, ключ строки) {return map.entrySet(). stream(). filter (e → StringUtils.equalsIgnoreCase(e.getKey(), key)). findFirst(). get().getValue(); } }