루프의 다음 항목으로 이동하려는 Java 8 foreach 스트림에 문제가 있습니다. 내가 좋아하는 명령을 설정할 수 없습니다 continue;
만,return;
작동하지만이 경우 루프를 종료합니다. 루프의 다음 항목으로 이동해야합니다. 어떻게 할 수 있습니까?
예 (작동하지 않음) :
try(Stream<String> lines = Files.lines(path, StandardCharsets.ISO_8859_1)){
filteredLines = lines.filter(...).foreach(line -> {
...
if(...)
continue; // this command doesn't working here
});
}
예 (작동) :
try(Stream<String> lines = Files.lines(path, StandardCharsets.ISO_8859_1)){
filteredLines = lines.filter(...).collect(Collectors.toList());
}
for(String filteredLine : filteredLines){
...
if(...)
continue; // it's working!
}
답변
사용 return;
하면 잘 작동합니다. 전체 루프가 완료되는 것을 막지는 않습니다. forEach
루프 의 현재 반복 실행 만 중지됩니다 .
다음과 같은 작은 프로그램을 시도해보십시오.
public static void main(String[] args) {
ArrayList<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("b");
stringList.add("c");
stringList.stream().forEach(str -> {
if (str.equals("b")) return; // only skips this iteration.
System.out.println(str);
});
}
산출:
a
c
return;
이 b
반복에 대해 어떻게 실행 되는지 확인하십시오 . 그러나 c
다음 반복에서는 잘 인쇄됩니다.
왜 이것이 작동합니까?
처음에는 동작이 직관적이지 않은 것처럼 보이는 이유는 return
전체 메서드의 실행을 방해하는 명령문에 익숙하기 때문 입니다. 따라서이 경우 main
메서드 실행이 전체적으로 중지 될 것으로 예상합니다 .
그러나 이해해야 할 것은 다음과 같은 람다 표현식입니다.
str -> {
if (str.equals("b")) return;
System.out.println(str);
}
… 정말 그 main
방법 안에 편리하게 위치해 있음에도 불구하고 방법과 완전히 분리 된 고유 한 “방법”으로 간주 되어야합니다. 따라서 return
실제로이 문은 람다 식의 실행 만 중지합니다.
두 번째로 이해해야 할 사항은 다음과 같습니다.
stringList.stream().forEach()
… 실제로는 모든 반복에 대해 람다 식을 실행하는 일반적인 루프입니다.
이 두 가지 점을 염두에두고 위의 코드는 다음과 같은 방법으로 다시 작성할 수 있습니다 (교육용으로 만 해당).
public static void main(String[] args) {
ArrayList<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("b");
stringList.add("c");
for(String s : stringList) {
lambdaExpressionEquivalent(s);
}
}
private static void lambdaExpressionEquivalent(String str) {
if (str.equals("b")) {
return;
}
System.out.println(str);
}
이 “덜 마법”코드에 해당하는 코드를 사용하면 return
명령문 의 범위 가 더욱 명확 해집니다.
답변
또 다른 해결책 : 반전 된 조건으로 필터를 통과하십시오. 예 :
if(subscribtion.isOnce() && subscribtion.isCalled()){
continue;
}
대체 가능
.filter(s -> !(s.isOnce() && s.isCalled()))
가장 간단한 방법은 “return”을 사용하는 것 같습니다. 그러나.
답변
전달하는 람다 forEach()
는 스트림에서받은 각 요소에 대해 평가됩니다. 반복 자체는 람다 범위 내에서 볼 수 없으므로 C 전 처리기 매크로 인 continue
것처럼 할 수 없습니다 forEach()
. 대신 나머지 문을 조건부로 건너 뛸 수 있습니다.
답변
if
continue 대신 간단한 문을 사용할 수 있습니다 . 따라서 코드를 사용하는 대신 다음을 시도해 볼 수 있습니다.
try(Stream<String> lines = Files.lines(path, StandardCharsets.ISO_8859_1)){
filteredLines = lines.filter(...).foreach(line -> {
...
if(!...) {
// Code you want to run
}
// Once the code runs, it will continue anyway
});
}
if 문의 술어는 if(pred) continue;
명령문 의 술어와 반대 이므로 !
(논리적 아님)을 사용하십시오.