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

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

Я пытаюсь изменить некоторые для каждого цикла на 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;
    }
}

с lambda

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

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

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

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

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

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

Посмотрим, как мы это сделаем, мы можем сделать это со следующим:

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

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

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

Это также включает в себя еще две точки:

  • Код против интерфейсов, поэтому код от List<E> более ArrayList<E>.
  • Используйте вывод алмаза для параметра типа в new ArrayList<>(), вы все-таки используете Java 8.

Теперь на второй пункт:

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

Ответ 4

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

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