Возврат из lambda forEach () в java


Я пытаюсь изменить некоторые циклы for-each на lambda forEach()-методы для обнаружения возможностей лямбда-выражений. Представляется возможным следующее:

ArrayList<Player> playersOfTeam = new ArrayList<Player>();      
for (Player player : players) {
    if (player.getTeam().equals(teamName)) {
        playersOfTeam.add(player);
    }
}

С лямбда forEach()

players.forEach(player->{if (player.getTeam().equals(teamName)) {playersOfTeam.add(player);}});

но следующий не особенно конечно интересно наблюдать:

for (Player player : players) {
    if (player.getName().contains(name)) {
        return player;
    }
}

С лямбда

players.forEach(player->{if (player.getName().contains(name)) {return player;}});

что-то не так в синтаксисе последней строки или невозможно вернуться из forEach() способ?

4 55

4 ответа:

The return там возвращается из лямбда-выражения, а не от содержания метода. Вместо forEach вам нужно filter потока:

players.stream().filter(player -> player.getName().contains(name))
       .findFirst().orElse(null);

здесь filter ограничивает поток теми элементами, которые соответствуют предикату, и findFirst затем возвращает Optional С первой соответствующей записью.

это выглядит менее эффективным, чем подход для цикла, но на самом деле findFirst() может короткое замыкание - оно не производит весь фильтрованный поток и затем извлеките из него один элемент, а он фильтрует только столько элементов, сколько ему нужно, чтобы найти первый соответствующий. Вы также можете использовать findAny() вместо findFirst() если вы не обязательно заботитесь о получении первый соответствующий игрок из (заказанного) потока, но просто любой соответствующий элемент. Это позволяет повысить эффективность при наличии параллелизма.

Я предлагаю вам сначала попытаться понять Java 8 во всей картине, самое главное в вашем случае это будут потоки, лямбды и ссылки на методы.

вы должны никогда преобразование существующего кода в код Java 8 на построчной основе, вы должны извлечь функции и конвертировать их.

в вашем первом случае я определил следующее:

  • вы хотите добавить элементы входной структуры в выходной список, если они соответствуют некоторому предикату.

давайте посмотрим, как мы это делаем, мы можем сделать это следующим образом:

List<Player> playersOfTeam = players.stream()
    .filter(player -> player.getTeam().equals(teamName))
    .collect(Collectors.toList());

что вы делаете здесь:

  1. превратите свою входную структуру в поток (я предполагаю, что она имеет тип Collection<Player>, теперь у вас есть Stream<Player>.
  2. отфильтровать все нежелательные элементы с помощью Predicate<Player>, сопоставление каждого игрока с логическим true, если он хочет быть сохранен.
  3. соберите полученные элементы в a список, с помощью Collector, здесь мы можем использовать один из стандартных коллекторов библиотеки, который Collectors.toList().

это также включает в себя два момента:

  1. код против интерфейсы, поэтому кодекс в отношении List<E> over ArrayList<E>.
  2. используйте алмазный вывод для параметра типа в new ArrayList<>(), вы используете Java 8, в конце концов.

теперь перейдем ко второму пункту:

вы снова хотите конвертировать что-то из устаревшей Java в В Java 8, не глядя на картину. На эту часть уже ответили @IanRoberts, хотя я думаю, что вам нужно сделать players.stream().filter(...)... над тем, что он предложил.

вот что мне помогло:

List<RepositoryFile> fileList = response.getRepositoryFileList();
RepositoryFile file1 = fileList.stream().filter(f -> f.getName().contains("my-file.txt")).findFirst().orElse(null);

принято от Java 8 поиск конкретного элемента в списке с лямбда

Если вы хотите вернуть логическое значение, то вы можете использовать что-то вроде этого (гораздо быстрее, чем фильтр):

players.stream().anyMatch(player -> player.getName().contains(name));