1. 리팩토링
1) 어서션 도입
- 어서션 : 프로그램의 의도를 확실히 밝히면서 실행 시 조건이 반드시 성립함을 보장
2) 리팩토링 카탈로그
이름 | 어서션 도입(Introduce Assertion) |
상황 | 코드 속에 성립해야 할 조건이 있음 |
문제 | 주석으로 ‘이런 조건이 성립한다'라고 적어도 프로그램 실행 시 확인되지 않음 |
해법 | 어서션 넣기 |
결과 |
o 해당 부분에서 성립해야 할 조건이 명확해지고 소스 코드의 가독성이 좋아짐
o 버그를 빨리 발견 가능함
o 어서션을 활성화하면 어서션이 성립하는지 자동으로 확인 가능함
o 어서션을 비활성화하면 어서션이 무시되어 성능이 개선됨
x 어서션을 지나치게 사용하면 오히려 읽기 어려워짐
|
주의 |
• 자바 컴파일러는 어서션을 무효화해도 어서션 부분 코드를 삭제하지 않음
• 어서션 안에 부수효과가 있는 코드를 작성하면 안 됨
• 어서션을 일반 에러 처리 대신에 사용하면 안 됨
|
2. 예제 프로그램
클래스 명 | 역할 |
SortSample | Int[]를 정렬하는 클래스 |
Main | 동작 확인용 클래스 |
1) 리팩토링 전
public class SortSample {
private final int[] _data;
public SortSample(int[] data) {
_data = new int[data.length];
System.arraycopy(data, 0, _data, 0, data.length);
}
public void sort() {
for (int x=0; x < _data.length -1; x++) {
int m=x;
for(int y = x + 1; y < _data.length; y++) {
if (_data[m] > _data[y]) {
m = y;
}
}
// 여기서 _data[m]은 _data[x] ~ _data[_data.length - 1]의 최솟값이어야 함
int v = _data[m];
_data[m] = _data[x];
_data[x] = v;
// 여기서 _data[0] ~ _data[x + 1]은 이미 정렬되어 있어야 함
}
}
public String toString() {
StringBuilder buffer = new StringBuilder();
buffer.append("[ ");
for (int i = 0; i < _data.length; i++) {
buffer.append(_data[i]);
buffer.append(", ");
}
buffer.append("]");
return buffer.toString();
}
}
- 선택 정렬을 이용하여 값들을 정렬하는 방식이다.
import java.util.Random;
public class Main {
private static final Random random = new Random(1234);
private static void execute(int length) {
//난수로 데이터 작성
int [] data = new int[length];
for ( int i=0; i < data.length; i++) {
data[i] = random.nextInt(data.length);
}
//데이터 표시
SortSample sorter = new SortSample(data);
System.out.println("BEFORE:" + sorter);
//정렬해서 표시
sorter.sort();
System.out.println(" AFTER:" + sorter);
System.out.println();
}
public static void main(String[] args) {
execute(10);
execute(10);
execute(10);
execute(10);
execute(10);
}
}
2) 리팩토링 실행
① 어서션 도입
⑴ 소스 코드에서 '성립해야 할 조건' 찾기
-> SortSample에서 주석처리한 부분
⑵ 조건을 포함한 어서션 작성
assert isMin(m, x, _data.length – 1);
assert isSorted(0, x + 1);
- isMin(pos, start, end) : 인덱스 pos에 있는 값이 인덱스 start이상 end이하 범위의 값 중에서 최솟값이면 true 반환
- isSorted(start, end) : 인덱스가 start이상 end이하인 범위가 정렬되어 있으면 true 반환
⭐ 어서션 도입시 부수효과(프로그램 동작 변화)가 없어야 한다.
없어야 하는 이유 : 어서션은 활성화, 비활성화 할 수 있기 때문에 활성화 여부에 따라 객체의 동작에 영향을 주면 안됨
⑶ 적혀 있던 주석 삭제
⑷ 컴파일 해서 테스트
3) 리팩토링 후
public void sort() {
for (int x=0; x < _data.length -1; x++) {
int m=x;
for(int y = x + 1; y < _data.length; y++) {
if (_data[m] > _data[y]) {
m = y;
}
}
assert isMin(m, x, _data.length - 1);
int v = _data[m];
_data[m] = _data[x];
_data[x] = v;
assert isSorted(0, x + 1);
}
}
...
private boolean isMin(int pos, int start, int end) {
for(int i = start; i <= end; i++) {
if(_data[pos] > _data[i]) {
return false;
}
}
return true;
}
private boolean isSorted(int start, int end) {
for (int i = start; i < end; i++) {
if(_data[i] > _data[i+1]) {
return false;
}
}
return true;
}
- java 명령어 기본값은 어서션 비활성화이기 때문에 -ea 옵션을 지정해야 한다.
명령어 | 옵션 | 의미 |
java | -ea | 어서션을 활성화함(시스템 클래스 제외) |
Java | -enableassertions | 어서션을 활성화함 == -ea |
Java | -da | 어서션을 비활성화함 (시스템 클래스 제외) |
java | -disableassertions | 어서션을 비활성화함 == -da |
Java | -ea: 클래스명 | 지정한 클래스로 어서션을 활성화함 |
Java | -ea: .... | 지금 작업 디렉터리의 익명 패키지로 어서션을 활성화 |
java | -ea :패키지명 | 지정한 패키지와 서브 패키지로 어서션을 활성화 |
Java | -da : 클래스명 | 지정한 클래스로 어서션을 비활성화함 |
Java | -da:... | 지금 작업 디렉터리의 익명 패키지로 어서션을 비활성화 |
Java | -da : 패키지명 | 지정한 패키지와 서브 패키지로 어서션을 비활성화 |
Java | -esa | 시스템 클래스로 어서션을 활성화함 |
Java | -enablesystemassertions | 시스템 클래스로 어서션을 활성화함 == -esa |
Java | -dsa | 시스템 클래스로 어서션을 비활성화함 |
Java | -disablesystemassertions | 시스템 클래스로 어서션을 비활성화함 == -dsa |
3. 어서션 동작 확인
- 클래스 내에 일부로 에러를 넣어 어서션 동작을 확인할 수 있다.
4. 한 걸음 더 나아가기
1) 자바 어서션 문법
ⓐ assert expr;
- expr을 평가한다, 평가 결과가 true라면 아무 일도 일어나지 않고, false라면 예외가 발생함
ⓑ assert expr: option;
- expr을 평가, true라면 아무 일도 일어나지 않고, option 표현식도 평가되지 않음
- option 표현식은 expr 값이 false일 때만 평가된다. 부가정보를 제공할 수 있음 (왜 에러가 났는지?)
* exper는 boolean 표현식이고, option 값을 가질 수 있다
2) 어서션은 에러 처리를 대신할 수 없음
3) 자바 어서션은 클래스 라이브러리가 아님
- assert는 자바 언어 키워드로 취급한다. 왜냐면 클래스 라이브러리가 아닌 자바 언어 사양에 포함되어 있기 때문
4) 어서션 완전삭제
- da옵션으로 비활성화 해도 코드는 클래스 파일안에 남아있음
private static final boolean ASSERT = true // 삭제하려면 false
...
if(ASSERT) {
assert x>0;
}
- assert문을 if문으로 감싸서 false가 되면 실행되지 않음을 컴파일 시점에서 알수 있어서 조건 컴파일 가능
-> 메모리 절약, 성능 개선에 도움이 된다.
5) 다른 언어 환경의 어서션
- C에서 assert 있음
- C++ 에서 템플릿 써서 어서션 실행가능
- C#에는 어서션 기능이 없음
5. 정리
어서션은 사람과 컴퓨터 양쪽에 프로그래머의 의도를 전달하는 방법!
코드 안에서 '성립해야 할 조건' 이라면 주석이 아닌 어서션을 도입하자!
'Major > Java' 카테고리의 다른 글
[자바로 배우는 리팩토링 입문] 5장 메서드 추출 (0) | 2022.06.01 |
---|---|
[자바로 배우는 리팩토링 입문] 4장 널 객체 도입 (0) | 2022.04.15 |
[자바로 배우는 리팩토링 입문] 2장 제어 플래그 삭제 (0) | 2022.04.13 |
[자바로 배우는 리팩토링 입문] 1장 매직 넘버를 기호 상수로 치환 (0) | 2022.04.13 |
[자바로 배우는 리팩토링 입문] 0장 리팩토링이란 (0) | 2022.04.13 |