N° 01 — 목록
'분류 전체보기' (197)
-
Backend Development/JavaJava - 17. annotation-reflection
Spring이 @Autowired를 보고 의존성을 주입하는 원리 — 애너테이션과 리플렉션@Autowiredprivate UserService userService;이 코드를 실행하면 Spring은 어떻게 UserService 타입의 bean을 찾아서 userService 필드에 주입하는가? 정답은 리플렉션(reflection)이다 — 런타임에 클래스의 필드, 메서드, 애너테이션을 검사하고 조작하는 메커니즘. (Reflection API)리플렉션은 프레임워크(Spring, JUnit, Hibernate, Jackson)의 근간이지만, 잘못 쓰면 성능 저하, 캡슐화 파괴, 유지보수성 악화를 초래한다. 이 글은 애너테이션 정의, 리플렉션 API, 동적 프록시, 그리고 언제 리플렉션을 써야 하는지를 풀어간다.애..
-
Backend Development/JavaJava - 16. io nio
Files.readAllLines()가 파일이 10GB일 때 OOM을 내는 이유 — I/O 모델의 선택10GB 파일을 Files.readAllLines()로 읽었다. 파일이 작을 때는 잘 동작한다. 하지만 10GB 파일에서는 OutOfMemoryError가 발생한다 — 모든 줄을 메모리에 한 번에 올리기 때문이다. Files.lines()를 쓰면 한 줄씩 스트리밍으로 읽으므로 OOM 없이 처리할 수 있다. (Files API)10GB 파일을 읽었더니 OutOfMemoryError가 났다. 왜? 전체 파일을 메모리에 올렸기 때문이다. 이 글은 Files.lines()로 스트리밍 읽기를 하는 법, Path로 파일을 다루는 법, 그리고 레거시 java.io를 버려야 하는 이유를 풀어간다.java.io vs j..
-
Backend Development/JavaJava - 15. datetime
new Date()가 1900년을 더해야 하는 이유 — java.time이 해결한 날짜 API의 재앙// Java 1.1 (1997년)Date d = new Date(2024 - 1900, 1 - 1, 1);// 연도에서 1900을 빼고, 월은 0부터 시작 — 상식과 정반대이 API는 Java 1.0(1996년)에서 만들어졌고, 30년이 지나도 여전히 레거시 코드에 남아 있다. java.util.Date의 월은 0부터 시작하고, 연도는 1900을 빼야 하며, SimpleDateFormat은 thread-safe하지 않다. Java 8(2014년)의 java.time 패키지(JEP-150, JSR-310)가 이 재앙을 끝냈다. (java.time 패키지)이 글은 java.time의 핵심 타입들 — Inst..
-
Backend Development/JavaJava - 14. optional
Optional.get()를 호출하면 NPE가 없어지는가 — Optional의 설계 의도와 함정Optional를 도입하면 NullPointerException이 사라질까? — 아니다. Optional.get()을 빈 Optional에 호출하면 NoSuchElementException이 발생한다. Optional은 null을 없애는 도구가 아니라, "값이 없을 수 있다"는 사실을 타입 시스템으로 표현하는 도구다. (Optional API)"값이 없을 수도 있다"는 사실을 타입으로 표현하면 어떻게 될까? 이 글은 Optional이 NPE를 어떻게 예방하는지, 언제 쓰고 언제 쓰지 말아야 하는지를 풀어간다.Optional이 해결하는 문제 — "이 메서드는 null을 반환할 수 있습니다"Java 8 이전에는 메..
-
Backend Development/JavaJava - 13. stream
Stream 파이프라인에서 filter가 호출되지 않는 순간 — 지연 평가의 작동 원리list.stream() .filter(x -> { System.out.println("filter: " + x); return x > 5; }) .map(x -> { System.out.println("map: " + x); return x * 2; }) .findFirst();이 코드를 실행하면 전체 리스트를 순회하며 모든 요소에 filter와 map을 적용할까? — 아니다. 첫 번째로 조건을 만족하는 요소를 찾는 즉시 중단된다. findFirst()가 단 하나의 결과만 필요하므로, Stream은 그것만 계산한다. 이것이 지연 평가(lazy evaluation)다. (Stream API)지연 평가가 ..
-
Backend Development/JavaJava - 12. lambda functional
람다가 사실 익명 클래스가 아닌 이유 — 함수형 프로그래밍과 invokedynamic(x, y) -> x + y를 컴파일하면 익명 내부 클래스가 생성될까? 대부분의 Java 개발자는 그렇게 생각한다. 틀렸다. Java 8의 람다는 invokedynamic 바이트코드로 컴파일된다 — 런타임에 JVM이 람다 인스턴스를 생성하는 방법을 결정한다. (JEP-335, JLS §15.27)이 차이가 왜 중요한가? 익명 클래스는 매번 새 .class 파일을 만들고, 인스턴스를 생성할 때마다 객체를 할당한다. invokedynamic 방식은 JVM이 상황에 따라 인스턴스를 재사용하거나 동적으로 생성할 수 있어 더 효율적이다. 이 글은 람다가 실제로 어떻게 실행되는지, 메서드 참조로 코드를 어떻게 줄이는지, 그리고 "e..