38
자바(+스크립트)의 레이블 구문 쁠랚쓰하게 활용하기
자바 및 자바스크립트에서 레이블 구문을 활용하면 손 들어라.
그럼, 레이블 구문 활용법을 아는 사람? 손!
흠... 잘 안 쓴다.
괜찮다. 나도 잘 안 쓴다.
보통 자바(+스크립트)에서 레이블 구문을 활용하는 곳이라 하면
백이면 백, 반복문의 유연한 처리에서 활용할 것이다.
LABEL1:
for (int i = 0; i < 1e6; i++) {
for (int j = 0; j < 1e6; j++) {
if (j > 1e3) break LABEL1;
}
}
LABEL1:
for (let i = 0; i < 1e6; i++) {
for (let j = 0; j < 1e6; j++) {
if (j > 1e3) break LABEL1;
}
}
아마 이런 식일 것이다. 자바와 자바스크립트 개발자라면 어느 구문에 눈이 먼저 띄는지 알기 때문에 굳이 각 언어가 뭔지는 설명하지 않겠다.
일단, 자바 언어 설계에 있어서 자바 개발 팀은, goto
문의 악명이라면 언어 기초를 배운 너희들도 익히 알고 있을 것이다. 굳이 C 언어를 안 배우더라도 주위에서 goto
문에 대한 탄식을 쉽게 접할 정도다.
자바 개발 팀도 이걸 알기 때문에, 자바의 레이블은 C와는 달리 break
문으로 빠져나가게끔 하는 식으로만 지원하도록 디자인했다.
음? continue
문에도 레이블 지원하는데? 라고 하는 개발자가 분명 있을 것이다. 이건 나중에 다루도록 하겠다.
그럼 내가 뭔 말하려고 했냐면, 별거 없다. 반복문 아니라도 쓸 곳은 많다.
예를 들어 보자.
public void doWork() {
// 전에 뭐 좀 처리하자.
if(조건에 맞는 처리 시) {
// 공통 처리
// 조건에 맞는 처리 하고 싶다.
} else {
// 공통 처리만 한다.
}
// 공통적인 후처리 좀 하자.
}
public void doWorkWithLabel() {
// 전에 뭐 좀 처리하자.
LABEL1: {
// 공통 처리
if (이건 조건에 안맞는듯) break LABEL1;
// 조건에 맞는 처리 하고 싶다.
}
// 공통적인 후처리 좀 하자.
}
일단 두 메소드의 처리 흐름은 동일하다. 하지만 if
구문과 label
구문을 사용한 점이 차이점 되시겠다.
자, 보통이라면 전자처럼 조건에 따라 같은 구문을 쓰면서까지 경우로 나뉘어 처리할 것이다. 분명 나쁜 습관은 아니다. 익숙해서 안정감도 든다. 하지만 코드 중복에 의한 코드 품질이 떨어지고, 수정 시 경우의 수 만큼 수정해야 하니 생산성이 떨어진다.
이걸 레이블로 관리해보자. 레이블 블록을 정의해서, 조건에 안맞으면 그냥 break LABEL
문으로 레이블 블록을 종료하면 된다. 공통 처리는 한 곳에만 넣어도 되고, 조건에 안맞으면 바로 공통 후처리를 수행한 후 메소드를 종료한다.
내가 왜 이렇게 소개를 하나면, 아래 사례가 있어서 소개한다.
public boolean doWorkAndResult() {
if (처리 대상인가?) {
// 전에 뭐 좀 처리하자.
if(이건 스킵해야돼) {
return true;
} else {
// 이건 처리해야돼.
}
// 공통적인 후처리 좀 하자.
return true;
} else return false;
}
자, 처리 대상이 있고 처리해야 한다. 하지만 일부 스킵해야 하는 업무가 생긴다. 그럴 경우 넘어가면 된다. 하지만 후처리를 해야 하는데 깜박하고 안하는 사태가 생긴다. 예를 들면 쓴 파일을 정리한다던가, 리소스를 close()
메소드 등으로 해제하는 등의 여러 마무리 작업이 있을 것이다. 이걸 if
와 중단 구문으로만 의지하면 커버리지가 심히 안나오는 사태가 생긴다.
이걸 label
구문으로 손쉽게 해결해준다.
public boolean doWorkAndResult() {
if (처리 대상인가?) {
// 전에 뭐 좀 처리하자.
LABEL1: {
if(이건 스킵해야돼) break LABEL1;
// 이건 처리해야돼.
}
// 공통적인 후처리 좀 하자.
return true;
} else return false;
}
이걸 레이블 블록을 사용하여 특정 구문을 조건부로 수행하도록 바꾸어 보았다. 추가적으로 처리할 대상은 처리한 다음 마무리 하고, 스킵해야 할 대상은 스킵만 하고 공통적인 마무리 작업을 할 수 있다.
이정도만 해도 손쉽게 커버리지가 늘어나는 보기좋은 광경이 펼쳐질 수 있다.
물론 굳이 label
쓰기 싫다면 쓰지 않아도 된다. 쓰지 않는다면 아래와 같은 코드가 나올 것이다.
public boolean doWorkAndResult() {
if (처리 대상인가?) {
// 전에 뭐 좀 처리하자.
if(! 이건 스킵해야돼) {
// 이건 처리해야돼.
}
// 공통적인 후처리 좀 하자.
return true;
} else return false;
}
사실 반복문의 label
구문처럼, 반복문 외에서도 label
구문이 빛을 발하려면 중첨된 블록이 존재하는 것이 좋다. 가장 대표적인 예가 중첩된 if
문이겠지. if
문도 적당히 써야 하는데 이걸 if
문으로 의지한다면 콜백 지옥과 같은 구문을 만날 수 있다. 이걸 label
문이 해결해준다를 보여주기 위해 간단한 예제를 보여주었다.
자, continue label
문에 대해 설명하겠다. 이건 한글 문서 찾아보기 힘들 터이니 내가 친절하게 설명해주겠다.
다행히도 continue
문은 goto
문처럼 블록을 처음부터 다시 실행해주지 않고, 상태를 유지하면서 다시 레이블 구문을 실행하도록 해준다.
그래서 반복문에 레이블을 달고, 중첩 반복문을 단 다음, 각각 10번씩 반복한다고 치겠다.
중첩 반복문에서 2번째 반복 시 continue label
구문을 넣는다면,
다시 레이블이 달린 반복문으로 돌아갈 것이다. 하지만 레이블이 달린 반복문의 반복 위치는 0이 아닌, 다음 숫자에서 시작한다는 게 차이점이라 하겠다.
하지만 중첩 반복문이이 아닌 일반 레이블 반복문에서 continue label
일 써봐야 일반 continue
문과 다를 게 없다. 이건 break label
도 마찬가지. 즉, 반복문을 잇거나 종료할 때 하는 기능과 똑같다고 보면 된다.
다시한번 말하지만 자바와 자바스크립트 둘 다 동일한 사용법에 동일한 효과다.
자, 내가 아주 간단한 과제를 내 주고 마치도록 하겠다.
let c=0;
first: for (let i=0;i<1000;i++) {
for(let j=0;j<1000;j++){
if(j==2) continue first;
c++;
if(j==3) break first;
}
};
console.log(c);
여기서 console.log
메소드를 통해 출력할 변수 c
값의 결과를 도출하고, 증명하기 바란다.
여기에 댓글을 달고 가장 마음에 드는 댓글을 선정해서...
꼴리는대로 고른 커피 한 잔 드리도록 하겠다.
참고로 언제 선정하고 언제 주는지도 꼴리는대로지만 약속은 지키니 걱정 말도록.
끗.
38