JS 함수를 Java 메서드로 변환하는 3가지 핵심 패턴
JS 함수를 Java 메서드로 변환하는 3가지 핵심 패턴
프론트엔드 로직을 백엔드로 이식하거나, 레거시 JS 코드를 Java 서버로 옮기는 작업은 생각보다 자주 생긴다. 겉보기엔 단순한 if-else 분기라도, JavaScript와 Java 사이에는 타입 시스템이 다르기 때문에 조용히 버그가 숨어드는 지점이 있다.
이 글에서는 실제 변환 작업에서 마주친 3가지 패턴과 각각의 이유를 정리한다.
패턴 1: 문자열 비교 — == 대신 .equals()
JavaScript에서는 ==로 문자열을 비교해도 대부분 의도대로 동작한다.
if (prodTpCd == '2011') { ... }
Java에서 같은 방식으로 쓰면 컴파일은 되지만, 참조(reference) 동등성을 비교한다. String 리터럴이라면 String Pool 덕분에 우연히 통과되기도 하지만, 메서드 반환값이나 외부 입력값은 다른 객체 인스턴스일 수 있어서 false가 나온다.
// 잘못된 방법
if (prodTpCd == "2011") { ... }
// 올바른 방법
if ("2011".equals(prodTpCd)) { ... }
상수를 앞에 두는 이유는 NPE(NullPointerException) 방지다. prodTpCd가 null이어도 "2011".equals(null)은 false를 반환하지만, prodTpCd.equals("2011")은 즉시 예외를 던진다.
패턴 2: 배열 포함 검사 — includes() 대신 List.contains()
JS에서 배열 포함 여부를 확인할 때 Array.prototype.includes()를 쓴다. Java에서는 Collection.contains()가 대응한다.
JS 코드에서 이런 패턴을 종종 볼 수 있다.
cdList.includes(parseInt(prodTpCd)) || cdList.includes(prodTpCd)
parseInt를 함께 쓰는 이유는 JS의 느슨한 타입 때문이다. prodTpCd가 문자열로 들어올 수도, 숫자로 들어올 수도 있어서 양쪽 다 방어하는 것이다.
Java에서는 파라미터 타입을 String으로 고정하면 이 이중 체크가 필요 없다.
private static final List<String> CD_LIST = List.of("2006", "2007", "2019");
// 하나로 충분
if (CD_LIST.contains(prodTpCd)) { ... }
패턴 3: 공유 목록 — 전역 변수 대신 static final 상수
JS에서는 모듈 스코프나 전역 변수로 목록을 관리하는 경우가 많다.
const pd015CdList = [2001, 2002, 2003]; // 어딘가에 선언된 전역 변수
Java에서는 클래스 레벨의 private static final 상수로 선언하는 것이 관례다.
// Java 8 이하
private static final List<String> CD_LIST = Arrays.asList("2001", "2002", "2003");
// Java 9 이상 — 불변(immutable) 보장
private static final List<String> CD_LIST = List.of("2001", "2002", "2003");
List.of()는 Arrays.asList()와 달리 완전한 불변 리스트를 반환한다. add() 호출 시 UnsupportedOperationException이 발생하므로 의도치 않은 수정을 원천 차단한다.
변환 전후 비교
Before (JavaScript)
function getAuthMid(prodTpCd, taxtTpCd) {
let mid = '';
if (prodTpCd == '2011') {
mid = 'MID_A';
} else if (cdList.includes(parseInt(prodTpCd)) || cdList.includes(prodTpCd)) {
if (taxtTpCd == '1002' && (prodTpCd == "2006" || prodTpCd == "2007")) {
mid = 'MID_B';
} else {
mid = 'MID_C';
}
} else if (taxtTpCd == '1002') {
mid = 'MID_D';
} else {
mid = 'MID_E';
}
return mid;
}
After (Java)
private static final List<String> CD_LIST = List.of("2006", "2007", "2019");
public String getAuthMid(String prodTpCd, String taxtTpCd) {
String mid;
if ("2011".equals(prodTpCd)) {
mid = "MID_A";
} else if (CD_LIST.contains(prodTpCd)) {
if ("1002".equals(taxtTpCd)
&& ("2006".equals(prodTpCd) || "2007".equals(prodTpCd))) {
mid = "MID_B";
} else {
mid = "MID_C";
}
} else if ("1002".equals(taxtTpCd)) {
mid = "MID_D";
} else {
mid = "MID_E";
}
return mid;
}
정리
| 변환 포인트 | JS | Java |
|---|---|---|
| 문자열 비교 | a == 'value' | "value".equals(a) |
| 배열 포함 검사 | arr.includes(x) | list.contains(x) |
| 타입 이중 방어 | includes(parseInt(x)) \|\| includes(x) | String 타입 고정 후 contains(x) |
| 공유 목록 | 전역/모듈 변수 | private static final List<String> |
JS → Java 변환에서 버그가 숨어드는 지점은 대부분 타입 차이에서 온다. 문자열 비교와 컬렉션 API 두 가지만 정확히 이해하면 대부분의 로직 변환은 어렵지 않다.