[JAVA/기초] LineNumberReader + 1 문제JAVA/JAVA 기초2025. 6. 26. 19:48
Table of Contents
728x90
JDK 8을 JDK 17로 마이그레이션 하는중 생긴 문제이다.
LineNumberReader lnr = new LineNumberReader(new FileReader(file));
lnr.skip(Long.MAX_VALUE);
int lineCount = lnr.getLineNumber();
targetCnt = prevTargetCount + lnr.getLineNumber() - lineToSkipCount + 1;
파일 끝까지 쭉 스킵하고 라인 수를 가져오는 로직이다.
JDK 8 시절에는 +1 보정을 넣어서 타겟 수를 계산했다.
근데 마이그레이션 이후 같은 로직인데 값이 달라지기 시작했다.
문제의 주범
https://bugs.java.com/bugdatabase/view_bug?bug_id=JDK-8230342
HttpClient 소켓 누수 버그 수정
여기 시점에 입출력 스트림 처리 전반에 대한 안전성 패치가 들어갔다.
https://bugs.java.com/bugdatabase/view_bug?bug_id=8235792
HttpClient 커넥션 풀 관리 개선
LienNumberREader 스트림 처리 로직이 정밀해짐
이로인한 차이가 생겼다.
구버전
if (n - r > 0) {
prevChar = NONE; // skip 끝날 때 무조건 초기화
}
이렇게 되어있어서, EOF 직전에 읽은 값 다 날아갔다.
그래서 결과적으로 getLienNumber() 값이 0으로 남는 경우가 많았다.
즉 이는 언제는 0줄 언제는 1줄로 판단한다.
신버전
case -1: // EOF
if (prevChar == CHAR)
lineNumber++; // 마지막 줄 정확히 카운트
prevVhar 강제 초기화 로직을 제거했다.
EOF 직전 prevChar == CHAR 상태를 유지한다.
read() 내부 아래에서 로직이 정확히 1줄로 인정한다.
교훈
간단하게 +1 로직을 지워도 되는 문제였지만, 그렇게 했을 경우 진짜 문제를 모른 채로 해결하는 행위이기 때문에 나중에 똑같은 실수 반복하거나, +1을 지워서 생기는 문제를 인식하지 못할수 있었다.
이번 케이스에서 중요한 건:
- 버전업을 했으면, 내가 의존하는 JDK 내부 동작까지 바뀌었는지 무조건 확인해야 한다.
- 특히, LineNumberReader처럼 겉으로는 똑같이 보이는 로직이 내부적으로 정교하게 개선됐을 때 기존 로직이 그대로 남아있으면 오히려 그게 오류 원인이 된다.
- "값이 이상한데? +1 빼니까 정상인데? 이 정도로 넘어가면 결국 개발자가 JDK에 끌려다니는 구조가 된다.
- 이전에도 문제 분석없이 +1을 해서 어쩔 때는 0줄 어쩔때는 1줄인 문제가 있었다고 한다.
728x90
'JAVA > JAVA 기초' 카테고리의 다른 글
[Spring/기초] Pageable 자주 사용하지만 관심은 없었던 그 녀석 (0) | 2025.06.12 |
---|---|
[Java/기초] 인텔리제이 javadoc 자동화? (0) | 2025.04.05 |
[Java/기초] Exceptions 총정리 (0) | 2024.07.07 |
[Java/기초] 접근 제한자 (public, protected, default, private) (0) | 2024.04.12 |
[Java/기초] abstract (0) | 2024.03.04 |
@코딩하는 자연대생 :: 자연대생도 코딩을 하고 싶어