자바(+스크립트)의 레이블 구문 쁠랚쓰하게 활용하기
Tags: java, javascript, korean
Published: 2021-07-16 01:29:32

자바 및 자바스크립트에서 레이블 구문을 활용하면 손 들어라.

그럼, 레이블 구문 활용법을 아는 사람? 손!

흠... 잘 안 쓴다.
괜찮다. 나도 잘 안 쓴다.

보통 자바(+스크립트)에서 레이블 구문을 활용하는 곳이라 하면
백이면 백, 반복문의 유연한 처리에서 활용할 것이다.

```java
LABEL1:
for (int i = 0; i < 1e6; i++) {
  for (int j = 0; j < 1e6; j++) {
    if (j > 1e3) break LABEL1;
  }
}
```

```js
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` 문에도 레이블 지원하는데? 라고 하는 개발자가 분명 있을 것이다. 이건 나중에 다루도록 하겠다.

그럼 내가 뭔 말하려고 했냐면, 별거 없다. 반복문 아니라도 쓸 곳은 많다.
예를 들어 보자.

```java
public void doWork() {
  // 전에 뭐 좀 처리하자.
  if(조건에 맞는 처리 시) {
    // 공통 처리
    // 조건에 맞는 처리 하고 싶다.
  } else {
    // 공통 처리만 한다.
  }
  // 공통적인 후처리 좀 하자.
}
public void doWorkWithLabel() {
  // 전에 뭐 좀 처리하자.
  LABEL1: {
    // 공통 처리
    if (이건 조건에 안맞는듯) break LABEL1;
    // 조건에 맞는 처리 하고 싶다.
  }
  // 공통적인 후처리 좀 하자.
}
```

일단 두 메소드의 처리 흐름은 동일하다. 하지만 `if` 구문과 `label` 구문을 사용한 점이 차이점 되시겠다.

자, 보통이라면 전자처럼 조건에 따라 같은 구문을 쓰면서까지 경우로 나뉘어 처리할 것이다. 분명 나쁜 습관은 아니다. 익숙해서 안정감도 든다. 하지만 코드 중복에 의한 코드 품질이 떨어지고, 수정 시 경우의 수 만큼 수정해야 하니 생산성이 떨어진다.
이걸 레이블로 관리해보자. 레이블 블록을 정의해서, 조건에 안맞으면 그냥 `break LABEL` 문으로 레이블 블록을 종료하면 된다. 공통 처리는 한 곳에만 넣어도 되고, 조건에 안맞으면 바로 공통 후처리를 수행한 후 메소드를 종료한다.

내가 왜 이렇게 소개를 하나면, 아래 사례가 있어서 소개한다.

```java
public boolean doWorkAndResult() {
  if (처리 대상인가?) {
    // 전에 뭐 좀 처리하자.
    if(이건 스킵해야돼) {
      return true;
    } else {
      // 이건 처리해야돼.
    }
    // 공통적인 후처리 좀 하자.
    return true;
  } else return false;
}
```

자, 처리 대상이 있고 처리해야 한다. 하지만 일부 스킵해야 하는 업무가 생긴다. 그럴 경우 넘어가면 된다. 하지만 후처리를 해야 하는데 깜박하고 안하는 사태가 생긴다. 예를 들면 쓴 파일을 정리한다던가, 리소스를 `close()` 메소드 등으로 해제하는 등의 여러 마무리 작업이 있을 것이다. 이걸 `if` 와 중단 구문으로만 의지하면 커버리지가 심히 안나오는 사태가 생긴다.
이걸 `label` 구문으로 손쉽게 해결해준다.

```java
public boolean doWorkAndResult() {
  if (처리 대상인가?) {
    // 전에 뭐 좀 처리하자.
    LABEL1: {
      if(이건 스킵해야돼) break LABEL1;
      // 이건 처리해야돼.
    }
    // 공통적인 후처리 좀 하자.
    return true;
  } else return false;
}
```

이걸 레이블 블록을 사용하여 특정 구문을 조건부로 수행하도록 바꾸어 보았다. 추가적으로 처리할 대상은 처리한 다음 마무리 하고, 스킵해야 할 대상은 스킵만 하고 공통적인 마무리 작업을 할 수 있다.
이정도만 해도 손쉽게 커버리지가 늘어나는 보기좋은 광경이 펼쳐질 수 있다.
물론 굳이 `label` 쓰기 싫다면 쓰지 않아도 된다. 쓰지 않는다면 아래와 같은 코드가 나올 것이다.

```java
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` 도 마찬가지. 즉, 반복문을 잇거나 종료할 때 하는 기능과 똑같다고 보면 된다.

다시한번 말하지만 자바와 자바스크립트 둘 다 동일한 사용법에 동일한 효과다.

자, 내가 아주 간단한 과제를 내 주고 마치도록 하겠다.

```js
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` 값의 결과를 도출하고, 증명하기 바란다.
여기에 댓글을 달고 가장 마음에 드는 댓글을 선정해서...
꼴리는대로 고른 커피 한 잔 드리도록 하겠다.
참고로 언제 선정하고 언제 주는지도 꼴리는대로지만 약속은 지키니 걱정 말도록.

끗.