N° 01 — 목록
'Backend Development' (45)
-
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..
-
Backend Development/JavaJava - 11. generics
List과 List가 런타임에 같은 타입인 이유 — 제네릭과 타입 소거new ArrayList().getClass() == new ArrayList().getClass() — 이 표현식은 true다. List과 List는 런타임에 같은 클래스(ArrayList)다. 제네릭 타입 정보가 컴파일 후 사라지기 때문이다 — 이것이 타입 소거(type erasure)다. (JLS §4.6)타입 소거를 모르면, 리플렉션으로 제네릭 타입을 검사하려다 실패하고, 제네릭 배열을 만들려다 컴파일 에러를 만나고, 힙 오염(heap pollution)에 빠진다. 왜 Java는 이렇게 설계했을까? 이 글은 제네릭이 컴파일 후 어떻게 사라지는지, 그리고 와일드카드(PECS)로 무엇을 하는지 풀어간다.제네릭이 해결하는 문제 — 타..
-
Backend Development/JavaJava - 10. collections
HashMap에서 7개의 키가 충돌하면 어떤 일이 일어나는가 — 컬렉션 선택의 기준HashMap에 7개의 키를 넣었다. 버킷 하나에 8번째 충돌이 발생하는 순간, 내부 데이터 구조가 연결 리스트에서 레드블랙 트리로 바뀐다. (HashMap JavaDoc) 대부분의 개발자는 이 사실을 모른 채 HashMap을 쓴다. 그래야 할까? — 대부분의 경우 그래도 된다. 하지만 성능이 갑자기 저하되거나, 메모리가 예상보다 많이 쓰일 때, 이 내부 구조를 아는 것이 문제 해결의 열쇠가 된다.왜 ArrayList는 0.001초인데 LinkedList는 1초 걸릴까? 정답은 "메모리에 어떻게 배치되어 있는가"에 있다. 이 글은 List, Set, Map, Queue 각각이 내부적으로 어떻게 동작하는지를 풀어간다.컬렉션 ..