Category: JAVA

0

[JAVA POI] HSSFWorkbook vs XSSFWorkbook vs SXSSFWorkbook 비교

Apache POI Workbook 종류Apache POI는 Microsoft Office 파일을 처리하기 위한 Java 라이브러리입니다. Excel 파일을 다루기 위해 세 가지 주요 Workbook 구현체를 제공합니다. 📌 HSSFWorkbookHSSF (Horrible SpreadSheet Format) 는 Excel 97-2003 파일 형식(.xls)을 처리하는 구현체입니다. 특징 파일 형식: .xls (Excel 97-2003) 최대 행 수: 65,536행 (2^16) 최대 열 수: 256열 (2^8) 최대 Cell Style: 4,000개 메모리 사용: 중간 수준 (전체 파일을 메모리에 로드) 처리 속도: XSSF보다 빠름 사용 예시import org.apache.poi.hssf.usermodel.HSSFWorkbook;import org.apache.poi.ss.usermodel.*;import java.io.FileOutputStream;import java.io.IOException;public class HSSFExample { public static void main(String[] args) throws IOException { // HSSFWorkbook 생성 Workbook workbook = new HSSFWorkbook(); Sheet sheet = workbook.createSheet("Sample"); // 데이터 작성 Row row = sheet.createRow(0); Cell cell = row.createCell(0); cell.setCellValue("Hello, HSSF!"); // .xls 파일로 저장 try (FileOutputStream fileOut = new FileOutputStream("sample.xls")) { workbook.write(fileOut); } workbook.close(); }} 장점

0

[JAVA POI] - The maximum number of Cell Styles was exceeded.

문제 상황Apache POI를 사용하여 Excel 파일(.xlsx)을 생성하거나 수정할 때 다음과 같은 오류가 발생할 수 있습니다. java.lang.IllegalStateException: The maximum number of Cell Styles was exceeded.You can define up to 64000 style in a .xlsx Workbook 발생 원인1. Cell Style 생성 방식의 문제Excel의 .xlsx 파일 형식에서는 최대 64,000개의 Cell Style만 생성할 수 있습니다. 이 제한은 Excel 파일 포맷의 스펙에 정의된 하드 리미트입니다. 일반적으로 이 오류는 다음과 같은 상황에서 발생합니다: // 잘못된 예시 - 반복문 안에서 매번 새로운 스타일 생성for (int i = 0; i < rows.size(); i++) { Row row = sheet.createRow(i); Cell cell = row.createCell(0); // 매 셀마다 새로운 스타일을 생성 (문제!) CellStyle style = workbook.createCellStyle(); Font font = workbook.createFont(); font.setBold(true); style.setFont(font); cell.setCellStyle(style); cell.setCellValue(data.get(i));} 위 코드에서 10,000개의 행을 처리한다면, 10,000개의 동일한 스타일이 생성되어 메모리를 낭비하고 결국 64,000개 제한에 도달하게 됩니다.

0

우아한 종료 (Graceful Shutdown)

Graceful Shutdown이란?Graceful Shutdown은 애플리케이션이 종료될 때 현재 처리 중인 작업을 안전하게 완료하고, 리소스를 정리한 후 종료하는 방식입니다. 갑작스러운 종료(Abrupt Shutdown)와 달리, 진행 중인 요청을 처리하고 데이터 손실을 방지합니다. 왜 필요한가?일반적인 종료 문제점// 갑작스러운 종료 시 발생할 수 있는 문제들- 처리 중인 HTTP 요청이 중단됨- 데이터베이스 트랜잭션이 롤백됨- 파일 쓰기 작업이 중단되어 데이터 손실- 외부 API 호출이 타임아웃- 메시지 큐의 메시지가 손실됨 Graceful Shutdown의 이점 데이터 무결성: 진행 중인 트랜잭션을 완료 사용자 경험: 진행 중인 요청에 대한 정상 응답 리소스 정리: 연결, 파일, 스레드 등 정리 무중단 배포: 롤링 업데이트 시 서비스 중단 최소화 JVM Shutdown HookJVM은 종료 시 등록된 Shutdown Hook을 실행합니다. 기본 사용법

0

JAVA - 자바 버전별 주요 특징 총정리 (Java 8 ~ Java 25)

들어가며자바는 1996년 처음 등장한 이후 지속적으로 발전해왔습니다. 특히 Java 8 이후로는 6개월마다 새로운 버전이 출시되면서 빠르게 진화하고 있습니다. 이 글에서는 Java 8부터 최신 버전인 Java 25까지의 주요 특징들을 살펴보겠습니다. 각 버전의 핵심 기능들을 이해하면 현대적인 자바 개발을 더 효과적으로 할 수 있습니다. Java 8 (2014년 3월) - LTSJava 8은 자바 역사상 가장 혁명적인 변화를 가져온 버전입니다. 함수형 프로그래밍 패러다임을 본격적으로 도입하면서 자바의 코딩 스타일을 완전히 바꾸어 놓았습니다. 람다 표현식 (Lambda Expressions)람다 표현식은 익명 함수를 간결하게 표현할 수 있게 해주는 기능입니다. 기존에는 익명 내부 클래스를 사용해야 했던 코드를 훨씬 간결하게 작성할 수 있게 되었습니다. // Java 7 이전button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Button clicked!"); }});// Java 8 이후button.addActionListener(e -> System.out.println("Button clicked!")); 스트림 API (Stream API)

0

JAVA - 버전별 주요 특징과 예시

정리 기준 자바 8부터 25까지의 흐름을 LTS 위주로 묶고, 미리보기/인큐베이터 상태를 함께 표기했다. 코드 예제는 해당 버전에서 동작하도록 작성했고, 미리보기 기능은 --enable-preview 플래그가 필요하다. Java 8 (2014, LTS)람다, Stream API, Optional, 새로운 java.time 패키지가 등장해 함수형 스타일과 안전한 시간 처리의 기반이 마련되었다. 인터페이스에 default/static 메서드를 둘 수 있어 라이브러리 진화도 쉬워졌다. List<String> names = Arrays.asList("Java", "Kotlin", "Scala");List<String> upper = names.stream() .filter(s -> s.startsWith("J")) .map(String::toUpperCase) .collect(Collectors.toList()); Java 9 (2017)프로젝트 지그소로 JDK 자체와 애플리케이션을 모듈화할 수 있게 되었고, JShell 덕분에 REPL 실험이 편해졌다. HTTP 클라이언트가 인큐베이터로 공개되어 이후 표준화의 발판을 마련했다. // module-info.javamodule com.example.app { requires com.example.service; exports com.example.app.api;} Java 10 (2018)

0

[JAVA] - Cold Start

목차 [JAVA] - 가비지 컬렉션 튜닝 [JAVA] - Garbage Collection(가비지 컬렉션) [JAVA] - JVM (자바 가상 머신) 🧊 Cold Start란?Cold Start는 JVM이 애플리케이션이 처음 실행될 때 초기화 과정 때문에 발생하는 지연(latency) 을 의미합니다. 마치 추운 겨울날 자동차 시동을 걸 때 엔진이 따뜻해질 때까지 시간이 걸리는 것과 비슷합니다. 일반적인 서버 환경에서는 애플리케이션이 한 번 시작되면 계속 실행되기 때문에 이 문제가 크게 부각되지 않았습니다. 하지만 MSA 는 인스턴스가 빈번히 생성 및 소멸되고 여러 서버가 긴밀히 통신하는 환경입니다. 이로 인해 특정 시스템이 재부팅되면 연결된 다른 시스템의 응답 속도까지 지연되는 문제가 발생했으며, 무중단 배포·잦은 배포·오토스케일링 등으로 인해 기존 아키텍처보다 성능 지연 현상이 더 빈번하게 나타나게 되었고, 전체적인 서비스 성능 이슈의 문제가 됐습니다. 🚦 Cold Start가 발생하는 이유Java 애플리케이션은 네이티브 코드가 아닌 JVM 위에서 바이트코드 실행 방식으로 동작하기 때문에, 첫 실행 시 다음과 같은 과정에서 오버헤드가 발생합니다. 1. JVM 초기화 과정의 복잡성Java 애플리케이션이 시작될 때 여러 단계의 초기화 과정을 거쳐야 합니다:

0

[Java] - 가비지 컬렉션 히스토리

목차 [JAVA] - 가비지 컬렉션 튜닝 [JAVA] - Garbage Collection(가비지 컬렉션) [JAVA] - JVM (자바 가상 머신) 초기 GC들 (JDK 1.0~1.4)Serial GC 가장 오래된 GC 단일 스레드로 동작 작은 애플리케이션이나 클라이언트 환경에 적합 Stop-the-World 시간이 길어서 현재는 제한적으로 사용 Parallel GC (Throughput Collector) JDK 1.4에서 도입 멀티코어 환경에서 여러 스레드를 사용해 처리량을 개선 JDK 6~8에서 기본 GC 여전히 긴 정지 시간이 단점 저지연 목표 GC들 (JDK 1.4~)Concurrent Mark Sweep (CMS) GC

0

[JAVA] - 가비지 컬렉션 튜닝

목차 [JAVA] - 가비지 컬렉션 튜닝 [JAVA] - Garbage Collection(가비지 컬렉션) [JAVA] - JVM (자바 가상 머신) 참고 https://d2.naver.com/helloworld/37111 가비지 컬렉션 튜닝 전체적으로 GC(Minor GC + Major GC) 가 적게 발생하기 위해서는 우선적으로 객체를 적게 생성하면 된다. Old Generation 으로 넘어가는 객체의 수 최소화 (횟수) Full GC 시간 줄이기 (영역) 1. Old Generation 으로 넘어가는 객체의 수 최소화New Generation 의 경우 Old Generation 영역보다 작기 때문에 상대적으로 Stop The World 가 작게 발생한다.

0

Java - Collection Framework

Java - Collection FrameworkList 컬랙션 List 컬랙션은 객체를 일렬로 늘여 놓은 구조 를 가지고 있다. 객체를 인덱스로 관리하기 때문에 객체를 저장하면 인덱스가 부여되고 해당 인덱스를 이용해 검색, 삭제를 할 수 있다. List 컬랙션에서는 객체 자체를 저장하는 게 아니라 객체의 번지를 참조한다. 동일한 객체를 중복 저장할 수 있다. 대표적인 구현체로는 ArrayList, Vector, LinkedList 등이 있다. 메서드 설명 boolean add(E e) List 맨 끝에 데이터를 추가한 후 정상적으로 저장되면 true 실패하면 false 를 반환한다. void add(int index, E element) 주어진 인덱스 위치에 데이터를 추가한다. set(int index, E element) 주어진 인덱스 위치에 저장된 데이터를 변경한다. boolean contains(Object o) 주어진 데이터가 List에 있는지 확인한다. E get(int index) 주어진 인덱스에 저장된 데이터를 반환한다. isEmpty() List 에 데이터가 있는지 확인한다. int size() List 에저장 돼 있는 데이터의 전체 크기를 반환한다. E remove(int index) 주어진 인덱스에 위치한 데이터를 삭제한다. void clear() List 에 저장돼 있는 모든 원소들을 삭제한다. boolean remove(Object o) List 에서 전달받은 데이터에 해당 하는 모든 원소를 삭제한다. Set 컬랙션 저장 순서가 유지되지 않기 때문에 Index 가 존재하지 않는다. 대신, Iterator 를 이용해 Set 에 저장된 데이터를 가져올 수 있다. 객체를 중복해서 저장할 수 없고, 하나의 null 만 저장할 수 있다. 대표적인 구현체로는 HashSet, TreeSet 이 있다. 메서드 설명 boolean add(E e) 데이터를 Set 에 저장한 후 정상적으로 저장되면 true를 중복 객체면 false 를 반환합니다. boolean contains(Object o) 객체가 저장돼 있는지 여부를 리턴합니다. Iterator iterator() 저장된 객체를 한번씩 가져오는 반복자를 반환한다. isEmpty() Set 이 비어있는지 조사합니다. int Size() Set 에 저장돼 있는 전체 객체수를 리턴합니다. void clear() Set 에 저장된 모든 객체를 삭제 boolean remove(Object o) Set 에 저장된 주어진 객체를 삭제합니다. Map 컬랙션 Key, Value 형식 으로 데이터를 관리하는 자료구조 키는 중복 저장될 수 없지만 값은 중복 저장될 수 있다. 기존에 저장된 키와 동일한 키로 값을 저장하면 새로운 값으로 대체된다. 대표적인 구현체로는 HashMap, HashTable, LinkedHashMap, TreeMap 등이 있다. 메서드 설명 V put(K Key, V value) Map 에 주어진 키와 값을 추가해 저장되면 해당 값을 리턴합니다. boolean containsKey(Object Key) Map 에 주어진 키 가 있는지 확인합니다. boolean containsValue(Object value) Map 에 주어진 값 이 있는지 확인합니다. Set<Map.Entry<K,V>> entrySet() 모든 Map.Entry 객체를 Set에 담아 리턴합니다. Set keySet() 모든 키를 Set 객체에 담아서 리턴합니다. V get(Object key) 주어진 키에 해당하는 값을 리턴합니다. boolean isEmpty() Map 이 비어있는지 조사합니다. int Size() Map 에 저장돼 있는 전체 객체의 수를 리턴합니다. Collection values() Map 에 저장된 모든 값을 Collection 객체에 담아서 리턴합니다. void clear() 저장된 모든 Map.Entry를 삭제합니다. V remove(Object Key) 주어진 키와 일치하는 Map.Entry를 삭제하고 값을 리턴합니다.

0

Java - Collection Framework

Java - Collection FrameworkStack 먼저 들어간 데이터가 가장 마지막에 나오는 구조 (First In First Out) 메서드 설명 void push(E e) stack 최상단에 데이터를 추가한다. Element pop() stack 최상단 데이터를 반환한 후 스택 최상단 데이터를 삭제한다. Element peek() stack 최상단 데이터를 반환한다. boolean isEmpty() stack 이 비어있는지 확인한다. int size() stack 의 크기를 반환한다. Queue 메서드 설명 boolean add(E e) Queue 맨 뒤에 데이터를 추가한 후 정상적으로 수행했으면 True, 데이터 삽입에 실패하면 False 를 반환한다. Queue 에 여유 공간이 없어 실패한 경우 IllegalStateException 예외를 발생 시킨다. boolean offer(E e) Queue 맨 뒤에 데이터를 추가한 후 정상적으로 수행했으면 True, 데이터 삽입에 실패하면 False 를 반환한다. E element() Queue 맨 앞의 원소를 반환한다. E peek( ) Queue 맨 앞의 원소를 반환한다. Queue 가 비어있을 경우 null 을 반환한다. E poll( ) Queue 맨 앞의 원소를 반환한 후 삭제한다. Queue 가 비어있을 경우 null 을 반환한다. E remove() Queue 맨 앞의 원소를 삭제한다.

0

[JAVA] - Garbage Collection(가비지 컬렉션)

목차 [JAVA] - 가비지 컬렉션 튜닝 [JAVA] - Garbage Collection(가비지 컬렉션) [JAVA] - JVM (자바 가상 머신) 📌 가비지 컬렉션 동적 할당 받은 메모리 중에서 사용하지 않는 메모리를 해제해 메모리 누수를 막는 메모리 관리 기법 GC 가 등장하기 전에는 개발자가 직접 메모리를 할당하거나 해제해줘야 했습니다. 메모리를 직접관리하기 때문에 실수로 메모리 memory leak 을 없앨 수 있다. GC Root가 될 수 있는 대상들 Stack 영역의 데이터 Static 데이터 JNI에 의해 생성된 객체들 Mark And Sweep 알고리즘

0

JAVA - JWT

JAVA - JWT Jwts.builder(JwtBuilder) 를 이용해 Token 을 생성하고 Jwts.parserBuilder(JwtParserBuilder) 를 이용해 전달 받은 Token 을 Parsing 한다. public class JwtMain { public static void main(String args[]) { String jwt = Jwts.builder() .setSubject("test") .compact(); Jwt<Header, Claims> headerClaimsJwt = Jwts.parserBuilder() .build() .parseClaimsJwt(jwt); // Token 정보를 가져온다. System.out.println("token : " + jwt); // JWT Header 정보를 가져온다. System.out.println("JWT Header : " + headerClaimsJwt.getHeader()); // JWT Body(Claims) 정보를 가져온다. System.out.println("JWT Claims : " + headerClaimsJwt.getBody()); }} Token 에 서명을 진행하지 않았기 때문에 Signature 부분이 빠져있는 것을 확인할 수 있다. token : eyJhbGciOiJub25lIn0.eyJzdWIiOiJ0ZXN0In0.JWT Header : {alg=none}JWT Claims : {sub=test} JWT 암호화 (JWS) JwtBuilder 객체는 signWith 메소드를 이용해 Key 값과 암호 알고리즘 을 인자값으로 넘겨줘 서명한다. 서명의 유효성은 JwtParserBuilder 객체가 setSigningKey 메소드를 이용해 전달받은 Token 이 유효한지 확인한다. public class JwsMain { public static String key = "amF2YS1hcHBsaWNhdGlvbi1zZWN1cmUtc3R1ZHktand0LXNlY3JldGtleS1pcy1zaG91bGQtYmUtYmlnZ2VyLXRoYW4tNTEyYml0cw=="; public static Long tokenValidityInMilliseconds = 100000L; public static void main(String args[]) { Key secretKey = Keys.hmacShaKeyFor(key.getBytes()); String jwt = Jwts.builder() .setSubject("test") .signWith(secretKey, SignatureAlgorithm.HS512) // JWT 를 암호화 하기 위한 secret 과 알고리즘을 넣어준다. .compact(); Jws<Claims> claimsJws = Jwts.parserBuilder() .setSigningKey(secretKey) .build() .parseClaimsJws(jwt); Header header = claimsJws.getHeader(); Claims body = claimsJws.getBody(); System.out.println("token : " + jwt); System.out.println("JWT Header : " + header); System.out.println("JWT Claims : " + body); }}

0

[JAVA] - JVM (자바 가상 머신)

목차 [JAVA] - 가비지 컬렉션 튜닝 [JAVA] - Garbage Collection(가비지 컬렉션) [JAVA] - JVM (자바 가상 머신) JVM (자바 가상 머신) 자바 컴파일러에 의해 생성된 자바 바이트 코드(.class) 를 OS에 맞는 기계어로 변환해 실행할 수 있게 해준다.클래스 파일로 떨어질 수 있으면 어떤 언어라도 실행이 가능하다. (ex. kotlin) 자바 컴파일러에 의해 생성된 바이트 코드를 실행하는 표준이자 구현체다. JVM은 각 OS(운영체제) 에 맞게 설계가 돼 있다. 자바 바이트 코드만 있으면 JVM을 이용해 어느 운영체제에서나 실행이 가능하다. Stack 기반 가상 머신 JVM 구조 Class Loader, Memory, 실행 엔진(Execution Engine) 이 세가지로 구성 돼 있다.

0

HttpClient 사용하기 - Multipart Parameter 보내기

HttpClient 사용하기 HttpClient 사용하기 - Paramater 보내기 HttpClient 사용하기 - Multipart Parameter 보내기 HttpClient 사용하기 - Multipart Parameter 보내기 Client가 서버로 파일 을 전송하거나 한번에 여러개의 Form 데이터 를 보내기 위해 사용하는 방식이다. 이미지와 같은 Binary 데이터는 기존 application/x-www-form-urlencoded 나 application/json 과 같은 요청으로 적절치 않아 multipart/form-data 형태의 데이터로 요청을 보낸다. application/x-www-form-urlencoded 는 보내는 Paramater를 encoding 해서 전송한다. 데이터가 영숫자가 아닌 경우 3바이트로 표현하기 때문에 바이너리 파일을 전송할 경우 페이로드를 3배로 만들기 때문에 비효율 적이다. multipart/form-data 의 경우는 전송한 모든 문자를 인코딩하지 않은 형태로 보낸다. 의존성 추가하기// https://mvnrepository.com/artifact/org.apache.httpcomponents/httpmimeimplementation group: 'org.apache.httpcomponents', name: 'httpmime', version: '4.3.4' MultipartEntityBuilder 를 이용해 HttpEntity 객체 생성 MultipartEntityBuilder 를 이용해 쉽게 Text나 파일을 (Key, Value) 형태로 Request Body 에 넣을 수 있다. Text를 보낼때는 addTextBody 메소드를 이용해 값을 넣어주고 이미지나 파일 데이터를 보낼 때는 addBinaryBody 메소드를 이용해 Binary 파일 을 넣어주고 Content Type 으로 MULTIPART_FORM_DATA 를 명시해준다.