내가 부딪친 기술에 대한 조언을 듣고 싶습니다. 코드 스 니펫을 보면 쉽게 이해할 수 있지만 다음 단락에서 좀 더 자세히 설명합니다.중첩 된 Java try/finally 코드 샌드위치에 대한 조언
"코드 샌드위치"관용구를 사용하면 자원 관리를 처리하는 것이 일반적입니다. C++의 RAII 관용구에 익숙해지면서 Java로 전환하여 예외적 인 자원 관리를 발견하여 심하게 중첩 된 코드를 만들었습니다. 제어 흐름을 이해하는 데 어려움을 겪고 있습니다.
분명히 (java data access: is this good style of java data access code, or is it too much try finally?, Java io ugly try-finally block 및 그 이상) 나는 혼자가 아닙니다.
명시 적으로 프로그램 상태를 유지 :
나는이에 대처하기 위해 다른 솔루션을 시도resource1aquired
,fileopened
..., 및 정리 조건 :if (resource1acquired) resource1.cleanup()
...하지만 명시 적으로 프로그램 상태를 복제 오히려 피해야 변수 - 런타임은 상태를 알고 있으므로 신경 쓰지 않아도됩니다.랩 기능의 모든 중첩 된 블록 - 훨씬 더 힘들어에서 결과를 제어 흐름에 따라, 정말 어색 함수 이름있게하기 :
runResource1Acquired(r1)
,runFileOpened(r1, file)
, ...
그리고 마지막으로 나는 관용구에 도착 대신이의
:
,321도 개념 상 일부 research paper on code sandwiches의 지원 0도우미 구성을 사용하면 보상 코드가 송신자 옆에있는보다 선형 구조에 도달 할 수 있습니다.
class Compensation {
public void compensate(){};
}
compensations = new Stack<Compensation>();
그리고 중첩 된 코드는 선형이된다 :
try {
connection = DBusConnection.SessionBus(); // may throw, needs cleanup
compensations.push(new Compensation(){ public void compensate() {
connection.disconnect();
});
connection.export("/MyObject", myObject); // may throw, needs cleanup
compensations.push(new Compensation(){ public void compensate() {
connection.unExport("/MyObject");
});
// unfolded try{}finally{} code
} finally {
while(!compensations.empty())
compensations.pop().compensate();
}
내가 기뻐 없었다 : 상관없이, 제어 흐름은 선형을 유지하고 정리 코드가 원래 코드를 시각적으로 옆에 얼마나 많은 뛰어난 경로. 게다가, 인위적으로 제한된 closeQuietly
메서드가 필요하지 않으므로 더 유연하게 사용할 수 있습니다 (즉, Closeable
개체 일뿐만 아니라 Disconnectable
, Rollbackable
및 기타 항목).
그러나 ...
다른 곳에서는이 기술에 대해 언급하지 않았습니다. 여기에 질문이 있습니다 :
이 기술이 유효합니까? 그것에 어떤 버그가 있습니까?
고마워요.
당신이 경우 어디에서 취급하지 않는 것 compensate() 메서드 내에서 예외가 발생할 수 있습니다. 그러면 후속 보상이 실행되지 않습니다. –
@ 케빈 : 참으로 - 너무 많은 C++ 관용구 : 소멸자가 던져서는 안되며, 여기에 그 관용구를 고집합니다. 예외를 처리하는 것은 구현을 보상하는 것입니다. – xtofl
@xtofl - 당신이'try-finally'를 사용하는 것과는 확연히 다른 것 같습니다. 코드 자체로 그 관용구를 채택 할 수 있고,'finally' 블록을 신경 쓰지 않아도됩니다. 게다가, 많은'Compensators'는 자연스럽게 예외를 던질 것입니다 (예를 들어, DB 리소스를 닫는'SQLException'); ** 모든 구현은 모든 예외를 개별적으로 잡아서 삼키기 위해 ** finally 블록을 일관되게 한 곳에서 처리합니다 **. 이러한 작업을 수행하는 것은 선택 사항이 아니며 (런타임 예외는 사양을 위반할 수 있으며 언제든지 발생할 수 있음) 복사 붙여 넣기를 권장합니다. –