Java의 람다 forEach ()에서 반환


97

forEach()람다 식의 가능성을 발견 하기 위해 일부 for-each 루프를 람다 메서드 로 변경하려고합니다 . 다음이 가능한 것 같습니다.

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()메서드 에서 반환 할 수 없습니까?


나는 아직 람다의 내부에 대해 잘 알지 못하지만, "무엇에서 돌아올 것인가?"라는 질문을 스스로에게 물었을 때, 처음에는 그것이 방법이 아니라는 의심이들 것입니다.
Gimby

1
@Gimby 예, return람다는 람다라고 부르는 것이 아니라 람다 자체에서 반환합니다. Ian Roberts의 답변에findFirst 표시된대로 스트림을 조기에 종료 ( "단락")합니다 .
Stuart Marks

답변:


121

return람다 식에서보다는 함유 방법에서이 반환된다. 대신 스트림 forEach이 필요 filter합니다.

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

여기 filter에서는 조건 자와 일치하는 항목으로 스트림을 제한 한 findFirst다음 Optional일치하는 첫 번째 항목과 함께 를 반환합니다 .

이는 for-loop 접근 방식보다 덜 효율적으로 보이지만 실제로 findFirst()단락 될 수 있습니다. 전체 필터링 된 스트림을 생성 한 다음 하나의 요소를 추출하지 않고 필요한만큼의 요소 만 필터링합니다. 첫 번째 일치하는 것을 찾으십시오. (주문 된) 스트림에서 첫 번째 일치하는 플레이어를 가져 오는 데 반드시 신경 쓰지 않고 일치하는 항목 만 있으면 findAny()대신 사용할 수도 있습니다 . 이렇게하면 병렬 처리가있을 때 효율성이 향상됩니다.findFirst()


고마워요, 그게 제가 찾던 것입니다! 탐색 할 Java8에는 많은 새로운 것이있는 것 같습니다. :)
samutamm

10
합리적인,하지만 난 당신이하지 사용하는 것이 좋습니다 orElse(null)Optional. 의 주요 요점은 Optionalnull (NPE로 이어짐)을 오버로딩하는 대신 값의 존재 여부를 나타내는 방법을 제공하는 것입니다. 사용 optional.orElse(null)하면 null로 모든 문제를 되 찾습니다. 호출자를 수정할 수없고 실제로 null이 예상되는 경우에만 사용합니다.
Stuart Marks

1
@StuartMarks 실제로 메서드 반환 유형을 수정하는 Optional<Player>것은 스트림 패러다임에 맞추는 더 자연스러운 방법이 될 것입니다. 람다를 사용하여 기존 동작을 복제하는 방법을 보여 주려고했습니다.
Ian Roberts

for (Part part : parts) if (! part.isEmpty ()) return false; 정말 짧은 것이 무엇인지 궁금합니다. 그리고 더 명확합니다. 자바 스트림 API는 자바 언어와 자바 환경을 진정으로 파괴했습니다. 2020 년 모든 자바 프로젝트에서 작업하는 악몽.
mmm

17

먼저 전체 그림에서 Java 8을 이해하려고 시도하는 것이 좋습니다. 가장 중요한 경우에는 스트림, 람다 및 메서드 참조가 될 것입니다.

당신이해야 결코 라인별로 자바 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. 를 통해 목록의 결과 요소를 수집합니다 Collector. 여기에서 표준 라이브러리 수집기 중 하나 인 Collectors.toList().

여기에는 다른 두 가지 사항도 포함됩니다.

  1. 인터페이스에 대한 코드이므로 List<E>over ArrayList<E>.
  2. 에서 유형 매개 변수에 다이아몬드 추론을 사용하십시오 new ArrayList<>(). 결국 Java 8을 사용하고 있습니다.

이제 두 번째 요점으로 넘어갑니다.

더 큰 그림을 보지 않고 레거시 Java를 Java 8로 다시 변환하고 싶습니다. 이 부분은 이미 @IanRoberts 에 의해 답변 되었지만 players.stream().filter(...)...그가 제안한 것을 극복 해야한다고 생각합니다 .


5

부울 값을 반환하려면 다음과 같이 사용할 수 있습니다 (필터보다 훨씬 빠름).

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


1

예외를 던질 수도 있습니다.

노트 :

가독성을 위해 스트림의 각 단계를 새 줄에 나열해야합니다.

players.stream()
       .filter(player -> player.getName().contains(name))
       .findFirst()
       .orElseThrow(MyCustomRuntimeException::new);

논리가 느슨하게 "예외 기반"인 경우 (예 : 코드에서 모든 예외를 포착하고 다음에 수행 할 작업을 결정하는 한 위치가있는 경우) 코드베이스를 배수로 흩 뜨리는 것을 피할 수있을 때만 예외 기반 개발을 사용하고 try-catch이러한 예외를 던지는 것은 예상하고 적절하게 처리 할 수있는 매우 특별한 경우입니다.)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.