Groovy 클로저에서 "계속"시뮬레이션을위한 최상의 패턴
그루비가 지원하지 않는 것 같습니다 break및 continue폐쇄 내에서. 이것을 시뮬레이션하는 가장 좋은 방법은 무엇입니까?
revs.eachLine { line ->
if (line ==~ /-{28}/) {
// continue to next line...
}
}
중단이 아닌 깔끔하게 계속 지원할 수 있습니다. 특히 eachLine 및 each와 같은 것들. 중단을 지원할 수없는 것은 이러한 메서드를 평가하는 방법과 관련이 있으며 메서드에 전달할 수있는 루프를 완료하지 않은 것에 대한 고려 사항이 없습니다. 계속 지원하는 방법은 다음과 같습니다.
최상의 접근 방식 (결과 값이 필요하지 않다고 가정).
revs.eachLine { line ->
if (line ==~ /-{28}/) {
return // returns from the closure
}
}
샘플이 정말 간단하다면 가독성에 좋습니다.
revs.eachLine { line ->
if (!(line ==~ /-{28}/)) {
// do what you would normally do
}
}
또 다른 옵션은 계속이 일반적으로 바이트 코드 수준에서 수행하는 작업을 시뮬레이션합니다.
revs.eachLine { line ->
while (true) {
if (line ==~ /-{28}/) {
break
}
// rest of normal code
break
}
}
중단을 지원하는 한 가지 가능한 방법은 예외를 사용하는 것입니다.
try {
revs.eachLine { line ->
if (line ==~ /-{28}/) {
throw new Exception("Break")
}
}
} catch (Exception e) { } // just drop the exception
특히 NumberFormatExceptions 또는 IOExceptions와 같은 실제 예외를 throw 할 수있는 해당 클래스에서 진행중인 다른 처리가있는 경우 다른 실제 예외를 마스킹하지 않도록 사용자 지정 예외 유형을 사용할 수 있습니다.
클로저는 루프 / 반복 구조가 아니기 때문에 중단되거나 계속 될 수 없습니다. 대신 반복 논리를 처리 / 해석 / 처리하는 데 사용되는 도구입니다. 다음과 같이 처리하지 않고 클로저에서 간단히 반환하여 주어진 반복을 무시할 수 있습니다.
revs.eachLine { line ->
if (line ==~ /-{28}/) {
return
}
}
중단 지원은 클로저 수준에서 발생하지 않지만 대신 클로저를 수락 한 메서드 호출의 의미에 의해 암시됩니다. 즉, 전체 컬렉션을 처리하기위한 컬렉션과 같은 것에 대해 "each"를 호출하는 대신 특정 조건이 충족 될 때까지 처리 할 find를 호출해야합니다. 대부분의 (모두?) 당신이 정말로하고 싶은 것은 클로저에서 깨어나야 할 필요가 있다고 느끼는 대부분의 경우, 당신의 논리적 인 필요뿐만 아니라 당신의 의도와도 일치하는 find 메소드를 만드는 반복하는 동안 특정 조건을 찾는 것입니다. 슬프게도 일부 API는 찾기 메소드를 지원하지 않습니다. 예를 들어 파일. 언어에 break / continue가 포함되어야하는지 논쟁하는 데 소요 된 모든 시간이 이러한 방치 된 영역에 find 메서드를 추가하는 데 많은 시간을 할애했을 수 있습니다. firstDirMatching (Closure c) 또는 findLineMatching (Closure c)와 같은 것은 "왜 ...에서 벗어날 수 없는가?"의 99 + %에 대해 먼 길을 갈 것입니다. 메일 링리스트에 나타나는 질문. 즉, MetaClass 또는 Categories를 통해 이러한 메서드를 직접 추가하는 것은 간단합니다.
class FileSupport {
public static String findLineMatching(File f, Closure c) {
f.withInputStream {
def r = new BufferedReader(new InputStreamReader(it))
for(def l = r.readLine(); null!=l; l = r.readLine())
if(c.call(l)) return l
return null
}
}
}
using(FileSupport) { new File("/home/me/some.txt").findLineMatching { line ==~ /-{28}/ }
Other hacks involving exceptions and other magic may work but introduce extra overhead in some situations and convolute the readability in others. The true answer is to look at your code and ask if you are truly iterating or searching instead.
If you pre-create a static Exception object in Java and then throw the (static) exception from inside a closure, the run-time cost is minimal. The real cost is incurred in creating the exception, not in throwing it. According to Martin Odersky (inventor of Scala), many JVMs can actually optimize throw instructions to single jumps.
This can be used to simulate a break:
final static BREAK = new Exception();
//...
try {
... { throw BREAK; }
} catch (Exception ex) { /* ignored */ }
Use return to continue and any closure to break.
Example
File content:
1
2
----------------------------
3
4
5
Groovy code:
new FileReader('myfile.txt').any { line ->
if (line =~ /-+/)
return // continue
println line
if (line == "3")
true // break
}
Output:
1
2
3
In this case, you should probably think of the find() method. It stops after the first time the closure passed to it return true.
With rx-java you can transform an iterable in to an observable.
Then you can replace continue with a filter and break with takeWhile
Here is an example:
import rx.Observable
Observable.from(1..100000000000000000)
.filter { it % 2 != 1}
.takeWhile { it<10 }
.forEach {println it}
참고URL : https://stackoverflow.com/questions/205660/best-pattern-for-simulating-continue-in-groovy-closure
'Nice programing' 카테고리의 다른 글
| Android 애플리케이션에서 런타임에 라이브러리를 동적으로로드 할 수 있습니까? (0) | 2020.11.11 |
|---|---|
| .NET 4.0 작업 패턴을 사용하여 HTTPClient .ReadAsAsync로 JSON을 배열 또는 목록으로 역 직렬화 (0) | 2020.11.11 |
| 이메일 주소를 사용자 ID로 사용할 때의 장단점은 무엇입니까? (0) | 2020.11.11 |
| 추상 클래스 vs. 인터페이스 vs. 믹스 인 (0) | 2020.11.11 |
| 순환 참조를 사용하여 JavaScript 객체 문자열 화 (JSON으로 변환) (0) | 2020.11.11 |