Devin.KR

Python 모델을 Java로 옮기기

65분 안팎

학습 목표

Java 메서드와 조건문으로 제목 검증을 옮겨 같은 사례를 비교합니다.

개념

번역 전에 같은 결과의 기준을 잡습니다

Python 참조 모델을 Java로 옮기는 목적은 파일 확장자를 바꾸는 일이 아닙니다. 앞 모듈에서 합의한 입력과 결과를 새 언어에서도 유지해야 다음 HTTP 작업의 기준이 생깁니다. 신입에게는 먼저 C02와 C03을 종이에 적게 합니다. 공백이 붙은 복습은 복습이 되고, 공백만 있는 제목은 EMPTY_TITLE입니다. 이 두 경로를 메서드의 줄과 연결할 수 있어야 AI가 낸 변환 코드를 검토할 수 있습니다.

이번 모듈의 실습 환경은 JDK 17과 Maven Wrapper입니다. 각 레슨의 starter.zip과 solution.zip은 별도 폴더에 풉니다. 학습자는 실습 폴더에서 ./mvnw test를 실행합니다. 사전 캐시가 있는 환경에서는 ./mvnw -o -q test도 가능합니다. Wrapper 실행 권한이 없다면 chmod +x mvnw로 복구합니다. 서버나 데이터베이스는 필요하지 않으며 테스트가 끝나면 Maven 프로세스도 종료됩니다.

관찰용 따라하기는 solution 폴더에서 테스트를 먼저 통과시킨 뒤 실행합니다. demos/Demo.java는 제공된 클래스의 동작을 출력하는 작은 실행 파일입니다. 관찰 결과를 이해한 다음 starter 폴더로 돌아가 지정된 결함을 고칩니다. 답안을 먼저 베끼는 대신 어떤 입력이 어느 분기를 선택했는지 설명합니다. 코드·명령 블록은 전체를 복사하고 명령은 README와 pom.xml이 있는 폴더에서 실행합니다.

자료형과 메서드 경계를 대응시킵니다

Python의 normalize_title(title)은 Java의 public static String normalize(Object value)에 대응합니다. String은 성공 반환값의 형식, Object는 검사 전 외부 입력을 받을 형식입니다. 입력을 String으로만 선언하면 숫자 제목을 직접 넣어 비교하기 어렵습니다. 이번 경계는 숫자·null·boolean을 실제로 거절하는 일을 보여 주기 위해 Object를 사용합니다. 앱 안에서 모든 변수에 Object를 쓰라는 뜻은 아닙니다.

public은 다른 클래스에서 호출할 수 있음을, static은 TitlePolicy 객체를 새로 만들지 않고 클래스 이름으로 호출함을 나타냅니다. 괄호 안은 매개변수이고 중괄호 안은 실행할 몸통입니다. 세미콜론은 문장 끝에 놓습니다. Java는 들여쓰기 대신 중괄호로 블록 경계를 정하지만 읽는 사람을 위해 들여쓰기도 맞춥니다. return은 문자열을 돌려주면서 그 메서드 호출을 끝냅니다.

value instanceof String title은 값이 문자열이면 title이라는 String 변수로 읽게 합니다. 앞에 느낌표를 두면 문자열이 아닌 조건이 됩니다. 그 조건에서 IllegalArgumentException을 발생시켜 INVALID_TITLE_TYPE을 전달합니다. 숫자를 String.valueOf로 바꾸면 실행은 쉬워지지만 앞 명세의 형식 오류를 정상 제목으로 바꾸는 결함입니다. null도 빈 문자열로 합치지 않고 형식 오류를 먼저 냅니다.

String은 내용을 직접 수정할 수 없는 값입니다. title.substring으로 앞뒤 공백을 제외한 구간을 얻어 clean에 받습니다. 정리 메서드를 호출하고 결과를 버리면 원본 title은 그대로입니다. 원본 입력과 정리한 결과를 별도 이름으로 두고 길이 검사는 clean에 수행합니다. 내부 공백을 split과 join으로 줄이는 기능은 계약에 없으므로 추가하지 않습니다.

길이와 공백은 언어 이름만으로 같아지지 않습니다

Python len은 이 계약에서 코드 포인트를 셉니다. Java String.length는 UTF-16 코드 유닛을 셉니다. 예를 들어 웃는 얼굴 이모지 하나는 Java length에서 2이지만 codePointCount에서는 1입니다. clean.codePointCount(0, clean.length())로 전체 구간의 코드 포인트 수를 얻습니다. 화면상 한 글자를 세는 기능은 아니며 여러 코드 포인트로 된 결합 이모지의 길이는 따로 늘어날 수 있습니다.

공백 제거도 Java strip을 그대로 대응시키면 차이가 생깁니다. Python은 NBSP와 NEXT LINE 같은 문자도 앞뒤에서 제거하지만 Java의 공백 판정은 같은 집합이 아닙니다. TitlePolicy.space는 앞 모델의 공백 집합을 명시해 두었습니다. 줄 바꿈·탭·일반 공백과 지정한 Unicode 공백만 제거하며 폭 없는 공백 U+200B는 남깁니다. 이번 계약에는 Unicode 정규화나 내부 공백 치환을 넣지 않습니다.

left와 right는 UTF-16 구간의 시작과 끝입니다. codePointAt으로 왼쪽 문자를, codePointBefore로 오른쪽 문자를 읽습니다. Character.charCount는 해당 코드 포인트가 차지하는 코드 유닛 수만큼 위치를 옮기게 합니다. 두 while은 앞과 뒤에서 공백인 동안만 진행합니다. 반복이 끝난 뒤 substring(left, right)을 한 번 호출하므로 가운데 공백은 그대로 보존됩니다.

clean.isEmpty이면 EMPTY_TITLE을 발생시킵니다. 그 뒤 코드 포인트 수가 40보다 클 때 TITLE_TOO_LONG입니다. 40 이상이라고 쓰면 허용 경계를 거절합니다. 검사 우선순위는 형식, 공백 제거 뒤 빈 값, 길이 상한입니다. 따라서 null에서 길이를 계산하거나 공백 제목에 긴 제목 오류를 내지 않습니다. 예외가 발생한 뒤 정상 반환 줄은 실행하지 않습니다.

오류와 실패를 다른 층에서 읽습니다

cannot find symbol은 변수나 메서드를 컴파일러가 찾지 못했다는 뜻입니다. TitlePolicy의 철자와 lab 패키지 import를 먼저 봅니다. incompatible types는 기대한 자료형과 대입하려는 값이 다르다는 뜻입니다. 이런 메시지는 아직 계약 사례를 실행하기 전 컴파일 단계에서 나옵니다. 업무 오류 코드를 바꿔 해결할 문제가 아니며 파일 이름과 줄 번호를 대조해 고칩니다.

AssertionFailedError에 expected와 actual이 나오면 테스트가 실행된 뒤 결과가 다른 상황입니다. lowerAndUpperBoundary가 실패했다면 40자 조건부터 확인합니다. supplementaryCharacters가 실패하면 String.length를 사용했는지 찾습니다. NullPointerException이 생기면 문자열 검사 전에 메서드를 호출했는지 봅니다. 테스트를 삭제하거나 기대값을 바꿔 초록색으로 만드는 대신 어떤 계약이 어긋났는지 적습니다.

로컬 실습의 수정 대상은 TitlePolicy.normalize의 길이 비교입니다. starter는 40자도 거절하지만 짧은 제목 등 일부 테스트는 통과합니다. solution과 비교하기 전에 1·40·41 코드 포인트, 숫자·null, 내부 공백, Unicode 앞뒤 공백을 각각 실행할 필요를 설명합니다. 테스트 이름을 입력 조건에 대응시키면 전체 테스트 수가 아니라 검증 범위를 말할 수 있습니다.

레슨 완료 시에는 같은 제목을 Python과 Java에 넣었을 때 무엇을 비교해야 하는지 답할 수 있어야 합니다. 문법 번역만 확인하지 않고 문자열 형식, 공백의 집합, 길이의 단위, 오류 우선순위를 확인합니다. 일반적인 메서드 오버로딩과 값 전달의 확장은 더 읽기로 연결합니다. 여기서는 제목 검증이라는 하나의 계약을 실행 사례로 설명하는 데 집중합니다.

실습 코드에서 찾을 부분

다음은 TitlePolicy.normalize에서 형식·빈 값·상한을 판단하는 부분입니다. 제공된 공백 계산은 유지하고 어느 검사에서 예외가 발생하는지 C03·C04·C06에 대응시킵니다.

if (!(value instanceof String title))
    throw new IllegalArgumentException("INVALID_TITLE_TYPE");
// 제공된 앞뒤 공백 구간 계산 후 얻은 clean에 적용합니다.
if (clean.isEmpty()) throw new IllegalArgumentException("EMPTY_TITLE");
if (clean.codePointCount(0, clean.length()) > 40)
    throw new IllegalArgumentException("TITLE_TOO_LONG");
return clean;

따라하기

관찰 프로젝트 준비

첫 레슨의 공통 안내대로 solution 폴더에서 테스트를 먼저 실행합니다. 아래 세 단계는 제공된 관찰 파일을 실행합니다. starter 결함을 고친 후에도 같은 명령으로 비교할 수 있습니다. 보고서에서 실제 실행된 테스트 수를 확인합니다.

./mvnw test

자료형과 오류 우선순위 비교

복습 사이 두 공백은 보존되어야 합니다. null과 숫자는 형식 오류이고 공백만 있는 문자열은 빈 제목 오류입니다. demos/Demo.java의 case 1에서 try가 감싼 호출과 예외를 출력하는 위치를 읽습니다.

java -cp target/classes demos/Demo.java 1

실행 결과

복습  정리
INVALID_TITLE_TYPE
INVALID_TITLE_TYPE
EMPTY_TITLE

이모지의 길이 단위 확인

case 2의 face는 40개 이모지입니다. UTF16과 CODEPOINT의 단위가 다른 이유를 예측한 뒤 ACCEPTED가 어느 단위를 나타내는지 비교합니다. 마지막 41개 입력은 길이 오류여야 합니다.

java -cp target/classes demos/Demo.java 2

실행 결과

UTF16=80
CODEPOINT=40
ACCEPTED=40
TITLE_TOO_LONG

특수 공백과 내부 보존 확인

case 3은 앞뒤 NBSP와 NEXT LINE을 제거하고 U+200B는 남깁니다. 대괄호 안의 제목과 ZERO_WIDTH 값을 비교하여 공백 집합을 계약으로 고정한 효과를 확인합니다.

java -cp target/classes demos/Demo.java 3

실행 결과

[복습]
ZERO_WIDTH=1

확인 문제

실습

TitlePolicy.normalize에서 40 코드 포인트를 허용하도록 결함을 고칩니다. 1·40·41, 이모지, null·숫자, 특수 공백·내부 공백을 검사하는 제공 테스트 7개를 유지합니다.

시작 코드·테스트 내려받기

실행 명령

./mvnw test

기대 결과

테스트 7개가 실패·오류·건너뜀 없이 통과하며 종료 코드는 0입니다.

모범 답안모범 답안 내려받기

더 읽기

면접 질문

  • AI가 만든 코드가 실행될 때 추가로 확인할 내용을 설명해 주시면 됩니다.