Java 40

Java 불변 객체와 방어적 복사: record로 안전한 도메인 만들기

Java 17 기준으로 불변 객체가 왜 중요한지, 방어적 복사로 캡슐화를 지키는 방법, record 활용과 얕은/깊은 복사 차이를 실무 관점에서 정리합니다.도입 (문제 상황)컬렉션이나 날짜 같은 값을 “그냥 getter로 꺼내줬는데”, 어느 순간부터 데이터가 몰래 바뀌어 버린 경험이 있으실 거예요. 특히 멀티스레드 환경이나 캐시, 이벤트 기반 처리에서는 이런 변경이 재현도 어렵고 원인 파악도 더 어렵습니다. 이럴 때 가장 강력한 방어막이 **불변 객체(Immutable Object)**와 **방어적 복사(Defensive Copy)**입니다.핵심 개념: Java 불변 객체가 중요한 이유 + 방어적 복사불변(Immutable)이 주는 실무적 이점불변 객체는 “한 번 만들어지면 상태가 바뀌지 않는 객체”입니..

JAVA 2026.02.26

Java 실무에서 자주 쓰는 디자인 패턴 5가지 (Strategy, Factory, Builder, Singleton, Observer)

Java 실무에서 자주 쓰는 디자인 패턴 5가지 (Strategy, Factory, Builder, Singleton, Observer)Java 17 기준으로 실무에서 가장 자주 마주치는 5가지 디자인 패턴을 “왜 쓰는지” 중심으로 정리하고, 바로 실행 가능한 간결한 예제로 감을 잡아봅니다.도입 (문제 상황)기능은 돌아가는데, 요구사항이 조금만 바뀌면 여기저기 if/else가 늘어나고 클래스가 비대해지는 경험을 해보셨을 거예요. “이 정도는 그냥 하드코딩해도 되지 않나?” 싶다가도, 다음 스프린트에 바로 후회하게 되죠. 실무에서 자주 쓰는 디자인 패턴 5가지는 이런 변경 비용을 줄이기 위한 최소한의 도구 세트에 가깝습니다.핵심 개념: Java 실무에서 5가지 패턴이 중요한 이유디자인 패턴은 “정답 코드”..

JAVA 2026.02.26

Java SOLID 원칙 — 코드로 이해하기 (Before/After 예제와 과도한 적용의 함정)

한줄 설명(meta description): Java 17 기준으로 SOLID 5원칙을 Before/After 코드로 빠르게 체감하고, 실무에서 과도한 추상화로 망하는 포인트까지 정리합니다.도입 (문제 상황)리팩토링을 하다 보면 “이 클래스는 책임이 너무 많다”, “확장에 닫혀 있다” 같은 피드백을 종종 받게 됩니다. 그런데 SOLID를 머리로는 알겠는데, 막상 코드로 바꾸려면 어디부터 손대야 할지 막막하실 때가 있어요. 이 글은 각 원칙을 Before/After 코드로 바로 체감하고, 과도한 적용으로 복잡도만 늘어나는 함정까지 함께 짚어봅니다.핵심 개념 (Java SOLID 원칙을 ‘왜’ 적용하는가)SOLID는 “정답 설계”가 아니라, 변경이 생겼을 때 안전하게 고칠 수 있는 코드로 가는 체크리스트에 ..

JAVA 2026.02.25

Java 모던 동시성 — ExecutorService & CompletableFuture로 스레드 풀과 비동기 처리 정리

Java 17 기준으로 ExecutorService 스레드 풀 관리와 CompletableFuture 비동기 조합 패턴을 실무 관점에서 정리합니다.도입 (문제 상황)외부 API를 5개 호출하는데, 하나가 느려지면 전체 응답이 같이 늦어지는 경험을 해 보셨을 거예요. 또는 “스레드를 직접 만들면 되지 않나?”로 시작했다가, 스레드가 늘어나면서 CPU 컨텍스트 스위칭과 장애 대응이 어려워진 적도 있을 겁니다. 이럴 때 필요한 게 스레드 풀(ExecutorService) 과 비동기 조합(CompletableFuture) 입니다.핵심 개념: Java에서 “스레드 관리”와 “비동기 조합”을 분리해서 생각하기 동시성에서 중요한 건 단순히 “동시에 실행”이 아니라, 자원을 예측 가능하게 쓰고(스레드 풀), 결과를 안..

JAVA 2026.02.25

Java 스레드 기초와 동기화(Thread, synchronized, volatile) 그리고 데드락까지 한 번에 정리

Java 17 기준으로 Thread/Runnable 차이, synchronized와 volatile의 의미, 데드락이 생기는 이유와 예방 패턴을 실무 관점에서 정리합니다.도입 (문제 상황)간단한 카운터를 여러 스레드에서 올렸는데 결과가 매번 달라지거나, 로그는 멀쩡한데 특정 환경에서만 간헐적으로 “멈춤”이 생긴 경험이 있으실 거예요. 멀티스레드는 “동시에 돌아가니 빨라지겠지”로 시작하지만, 동기화 규칙을 모르면 재현도 어려운 버그로 이어집니다.핵심 개념: Java 스레드와 동기화가 중요한 이유Java에서 스레드는 “CPU를 더 쓰는 기능”이라기보다 공유 상태(shared state)를 어떻게 안전하게 다룰지의 문제에 가깝습니다. 특히 아래 3가지를 구분해두면 사고가 크게 줄어듭니다.Thread vs Ru..

JAVA 2026.02.24

Java 파일 I/O 현대적으로 하기: Files/Path, try-with-resources, 인코딩까지 깔끔하게

Java 17 기준으로 Files/Path API와 try-with-resources를 활용해 안전하고 읽기 쉬운 파일 I/O를 구현하고, UTF-8 인코딩 이슈를 확실히 해결하는 방법을 정리합니다.도입 (문제 상황): Java 파일 읽기가 왜 자꾸 깨질까요?파일을 읽었는데 한글이 ???로 보이거나, 운영 서버에서만 줄바꿈이 이상하게 처리되는 경험 해보셨을 거예요. 게다가 스트림을 닫는 걸 깜빡해서 파일 핸들이 누수되거나, 예외 처리 코드가 본문보다 길어지는 경우도 흔합니다.Java 17에서는 이런 문제를 **Files/Path(NIO.2)**와 try-with-resources, 그리고 명시적 인코딩 지정으로 꽤 우아하게 정리할 수 있어요.핵심 개념: Files/Path + 명시적 Charset이 “현..

JAVA 2026.02.24

Java 17 java.time 완전 가이드: LocalDate/LocalDateTime/ZonedDateTime, 포맷팅, 레거시(Date) 변환

Java 17 기준으로 LocalDate/LocalDateTime/ZonedDateTime 선택 기준, DateTimeFormatter 포맷팅/파싱, 레거시 Date·Calendar·Timestamp 변환까지 실무 관점으로 정리합니다.1) 도입 (문제 상황)서버 로그는 UTC인데 화면에는 KST로 보여야 하고, DB에는 Timestamp가 들어가 있는데 API 요청은 "2026-02-22T10:30:00"처럼 문자열로 들어오는 상황을 자주 마주하실 거예요. 그때마다 Date, Calendar, SimpleDateFormat을 섞어 쓰다 보면 “왜 9시간이 밀렸지?” 같은 버그가 생기기 쉽습니다. Java 8부터의 java.time을 제대로 잡아두면 이런 문제를 안정적으로 줄일 수 있습니다.2) 핵심 개념..

JAVA 2026.02.23

Java Optional 올바르게 쓰기: of vs ofNullable, 안티패턴, 실무 가이드라인

Java 17 기준으로 Optional.of/ofNullable 차이부터 흔한 안티패턴, API 설계·서비스 코드에서의 실무 가이드라인을 정리합니다. 서비스 코드에서 null 체크를 줄이려고 Optional을 도입했는데, 오히려 get()이 난무하거나 Optional> 같은 코드가 생긴 적 있으실 거예요. 더 난감한 건 Optional.of() 때문에 운영에서 NPE가 터지는 경우입니다. Optional은 “null을 없애는 마법”이 아니라, 경계를 명확히 하는 도구에 가깝습니다.핵심 개념: Java Optional을 왜/어디에 써야 할까Optional의 핵심 가치는 “값이 없을 수 있음”을 타입으로 표현해서, 호출자가 그 가능성을 무시하기 어렵게 만드는 데 있습니다. 다만 이 장점은 적절한 경계(주로 ..

JAVA 2026.02.23

Java Stream 실전 활용 & 주의점: groupingBy, flatMap, Optional 연계부터 병렬 스트림 함정까지

Java 17 기준 Stream을 실무에서 자주 쓰는 groupingBy/flatMap/Optional 패턴으로 정리하고, 성능 이슈와 parallelStream 함정을 안전하게 피하는 방법을 설명합니다. Stream API를 “필터-맵-수집” 정도로만 쓰다 보면, 조금만 복잡한 요구사항(그룹핑, 중첩 컬렉션 펼치기, Optional 연계)이 나오자마자 코드가 급격히 읽기 어려워질 때가 있어요. 게다가 성능까지 신경 쓰기 시작하면 “Stream이 느린가?” “parallelStream으로 해결하면 되나?” 같은 고민이 따라옵니다. 이번 글에서는 실무에서 자주 부딪히는 패턴과 함정을 한 번에 정리해 보겠습니다.핵심 개념: Java Stream을 “읽기 좋게, 안전하게, 빠르게” 쓰는 기준1) groupin..

JAVA 2026.02.22

Java Stream API 기초: 생성 → 중간연산 → 최종연산으로 끝내는 filter/map/collect 패턴

Java 17 기준 Stream 파이프라인의 기본 흐름(생성-중간-최종)과 filter/map/collect 실전 패턴을 예제로 빠르게 익힙니다. 람다식을 배웠는데, 막상 리스트를 가공하려고 하면 for 문이 다시 늘어나기 시작할 때가 있어요. “필터링하고, 변환하고, 원하는 형태로 모으는” 작업이 반복되면 코드가 금방 지저분해집니다. 이럴 때 Stream API의 기본 흐름만 잡아두면, 대부분의 컬렉션 가공이 깔끔하게 정리됩니다.핵심 개념: Java Stream API 파이프라인(생성 → 중간연산 → 최종연산)Stream은 한마디로 데이터를 ‘흐름’으로 보고 단계별로 가공하는 파이프라인이에요. 중요한 포인트는 딱 3가지입니다.생성(Source): 어디서 데이터를 가져올지 결정합니다. (list.stre..

JAVA 2026.02.22