Я пытаюсь изменить некоторые циклы for-each на лямбда- 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()
метода?
return
внутри оператора лямбда возвращается из самой лямбды, а не из того, что называется лямбда. Досрочное прекращение потока («короткое замыкание») используется,findFirst
как показано в ответе Яна Робертса .Ответы:
Это
return
возвращается из лямбда-выражения, а не из содержащего метода. ВместоforEach
стрима нужноfilter
:players.stream().filter(player -> player.getName().contains(name)) .findFirst().orElse(null);
Здесь
filter
поток ограничивается теми элементами, которые соответствуют предикату, аfindFirst
затем возвращаетсяOptional
с первой совпадающей записью.Это выглядит менее эффективным, чем подход цикла for, но на самом деле
findFirst()
может привести к короткому замыканию - он не генерирует весь отфильтрованный поток, а затем извлекает из него один элемент, а фильтрует только столько элементов, сколько необходимо, чтобы найти первый подходящий. Вы также можете использоватьfindAny()
вместо этого,findFirst()
если вам не обязательно заботиться о получении первого совпадающего игрока из (упорядоченного) потока, а просто о любом соответствующем элементе. Это позволяет повысить эффективность при использовании параллелизма.источник
orElse(null)
наOptional
. Суть вOptional
том, чтобы предоставить способ указать наличие или отсутствие значения вместо перегрузки null (что приводит к NPE). Если выoptional.orElse(null)
его используете, он выкупает все проблемы с нулями. Я бы использовал его, только если вы не можете изменить вызывающего, и он действительно ожидает нуль.Optional<Player>
было бы более естественным способом вписаться в парадигму потоков. Я просто пытался показать, как продублировать существующее поведение с помощью лямбда-выражений.Я предлагаю вам сначала попытаться разобраться в Java 8 в целом, наиболее важно в вашем случае это будут потоки, лямбды и ссылки на методы.
Вы никогда не должны преобразовывать существующий код в код Java 8 построчно, вы должны извлекать функции и преобразовывать их.
В вашем первом случае я обнаружил следующее:
Давайте посмотрим, как мы это сделаем, мы можем сделать это следующим образом:
Что вы здесь делаете:
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(...)...
то, что он предложил.источник
Если вы хотите вернуть логическое значение, вы можете использовать что-то вроде этого (намного быстрее, чем фильтр):
источник
Вот что мне помогло:
List<RepositoryFile> fileList = response.getRepositoryFileList(); RepositoryFile file1 = fileList.stream().filter(f -> f.getName().contains("my-file.txt")).findFirst().orElse(null);
Взято из Java 8 Поиск определенного элемента в списке с помощью Lambda
источник
Вы также можете создать исключение:
Заметка:
Для удобства чтения каждый шаг потока следует перечислять с новой строки.
players.stream() .filter(player -> player.getName().contains(name)) .findFirst() .orElseThrow(MyCustomRuntimeException::new);
если ваша логика слабо «управляется исключениями», например, в вашем коде есть одно место, которое улавливает все исключения и решает, что делать дальше. Используйте разработку, управляемую исключениями, только тогда, когда вы можете избежать засорения своей базы кода множественными числами,
try-catch
и выброс этих исключений предназначен для очень особых случаев, которые вы ожидаете от них и с которыми можно правильно справиться.)источник