Возврат из 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()
?
Ответы
Ответ 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(...)...
по тому, что он предложил.
Ответ 3
Это помогло мне:
List<RepositoryFile> fileList = response.getRepositoryFileList();
RepositoryFile file1 = fileList.stream().filter(f -> f.getName().contains("my-file.txt")).findFirst().orElse(null);
Взято из Java 8 Поиск конкретного элемента в списке с лямбдой
Ответ 4
Если вы хотите вернуть логическое значение, вы можете использовать что-то вроде этого (намного быстрее, чем фильтр):
players.stream().anyMatch(player -> player.getName().contains(name));