자바 컬렉션 프레임워크(List, Set, Map) 동작 원리 분석

💡 핵심 요약 (Executive Summary)

본 가이드는 java 핵심 가이드 및 실전 아키텍처의 핵심 개념, 실전 구성 명령어 및 아키텍처 베스트 프랙티스를 다룹니다. 클라우드 네이티브 및 인프라 엔지니어링 실무에 즉시 활용 가능하도록 체계적으로 정리했습니다.

📑 Table of Contents

하위페이지

Spring


Roadmap

Java Collection

Map
Object → Map (Jackson.ObjectMapper)
java
ObjectMapper objectMapper = new ObjectMapper();
Person person = new Person(12, "kim");
Map<String, Object> map = objectMapper.convertValue(person, Map.class);
Map → String for Logging (Collection.Stream)
java
String resultSet =
        {{ map_var }}.entrySet()
                .stream()
                .map(e -> e.getKey() + "=" + String.join(", ", e.getValue()))
                .collect(Collectors.joining(" "));
log.debug(resultSet);
...
List
Array Parse with List (Lists or Arrays)
java
// List to Array
long[] longArr = Longs.toArray(longList);

// List to Array (Object)
String[] strArr = StringList.toArray(new String[0]);

// Array to List
Integer[] sourceArray = { 0, 1, 2, 3, 4, 5 };
List<Integer> targetList = Lists.newArrayList(sourceArray);
List<String> targetList2 = Arrays.asList(new String[] {""});
JSON
Object → JsonString (Jackson.ObjectMapper)

Object -> Json 변환과정은 Serialization 이라고 한다. Jackson은 String 이외에 file이나 stream에 쓰는것도 가능하다.

java
ObjectMapper objectMapper = new ObjectMapper();
Person person = new Person("Nicole", 20);

String personJson = objectMapper.writeValueAsString(person);

System.out.println(personJson);
JsonString → Object (Jackson.ObjectMapper)

Json -> Object 변환 과정은 Deserialization 이라고 한다. Serialization과 마찬가지로 file이나 stream에 쓰는것도 가능하다.

java
String personJson = "{isJsonString}"
Person jsonToPerson = objectMapper.readValue(personJson, Person.class);
Reactive Streams
비교 항목 Java Stream API WebFlux (Project Reactor)
작동 방식 Pull-based (동기) Push-based (비동기)
Blocking 여부 Blocking. 데이터를 다 모을 때까지 스레드가 대기함. Non-blocking. 데이터가 준비되면 알려달라고 예약함.
데이터 소스 이미 메모리에 있는 컬렉션 (List, Set 등) 언제 올지 모르는 데이터 흐름 (네트워크, DB 등)
사용 목적 대량의 데이터를 빠르게 계산 (병렬 처리 등) 적은 스레드로 많은 동시 요청을 효율적 처리
재사용성 한 번 소비하면 끝 (닫힘) 여러 번 구독(Subscribe) 가능
Java Stream
java
/* Stream.map() */
List<?> baseList = new ArrayList<>();
List<?> rtnList = baseList.stream().map(obj->{
	return obj.value
}).collect(Collectors.toList());

/** Map 내 모든 리스트 병합 */
((HashMap<String,List<String>>) obj).values().stream().flatMap(List::stream).collect(Collectors.toList()));

/** 표현식 설명 아래 모두 기능 동일*/
// .A(B::C) 종류 (.A(D->{})를 가정)
// 1. .A(D->D.C())
.map(Map.Entry::getValue) == .map(entry -> entry.getValue())
// 2. Consumer<T(D)> void : .A(D->B.C(D))
.forEach(System.out::println) == .forEach(item -> System.out.println(item))
// 3. Supplier<T(new)> retrun T : .A(()->B.C())
(Math::random) == (()->Math.random())
// 4. Function<T(D),T(B)> ? : .A(D->B.C(D))
(Interger::parseInt) == (str->Integer.parseInt(str));
// 5. Predicate<T(B)> return Boolean : .A(D->D.C())
(String::isEmpty)
// 이것을 단순화하려 해보았지만, 분석결과 사실 Functional Interface의 정의에 따라 모두 다른 결과일것으로 보임
WebFlux (Project Reactor)
java
//ClientRequest

//ClientResponse
response.bodyToMono()

//Body and Mono
Publisher.subscribe(
	value -> { //when then (Published value)
	},
	error -> { //when throwed
	},
	() -> { //when completed
	}
)
실패
java
//ClientResponse를 Publisher(bodyToMono(), bodyToFlux())를 사용하여 로깅
//외부 웹클라이언트의 이벤트에 의해 다중실행되는 메서드이므로 subscribe()-비동기-를 하게되면 에러발생.

/** 에러 예시 */
            clientResponse.bodyToMono(String.class)
                    .doOnNext(responseBody -> {
                        sb.append("\tBody: \n");
                        sb.append("\t\tContents: " + responseBody + " \n");
                    })
                    .doOnTerminate(()-> {
                        log.info(sb.toString());
                    })
                    .subscribe();
            return Mono.just(clientResponse);

/** 잘못된 예시 */
            clientResponse.bodyToMono(String.class)
                    .flatMap(responseBody -> {
                        sb.append("\tBody: \n");
                        sb.append("\t\tContents: " + responseBody + " \n");
                        log.info(sb.toString());
                        return Mono.empty();
                    });
            return Mono.just(clientResponse);
/*
java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-2
이 메시지는 다음을 나타냅니다:

block(), blockFirst(), 또는 blockLast()와 같은 블로킹 연산을 스레드 "reactor-http-nio-2"에서 사용하고 있다는 것입니다.
Reactor는 비동기 및 논블로킹 스트림 처리를 위해 설계되었으므로 블로킹 연산을 사용하면 문제가 발생할 수 있습니다.
*/

/** 방법 */
            clientResponse.bodyToMono(String.class)
                    .subscribeOn(Schedulers.elastic())
                    .subscribe(responseBody -> {
                        sb.append("\tBody: \n");
                        sb.append("\t\tCount: " + JsonParserFactory.getJsonParser().parseMap(responseBody).size() + " \n");
                        sb.append("\t\tContents: " + responseBody + " \n");
                        log.info(sb.toString());
                    });
//            }
            return Mono.just(clientResponse);

/* Steam을 즉시 종료하고 내용물을 꺼내기 */
Mono<String> mono = Mono.just("Hello, Reactor!");

mono
    .take(1)
    .subscribe(
        value -> {
            // 첫 번째 요소를 처리합니다.
            System.out.println("Received value: " + value);
        },
        error -> {
            // 에러 처리
        },
        () -> {
            // 완료 처리
        }
    );
메서드 입력(Input) 출력(Output) 리액터의 처리 (Unwrapping)
map T R (일반 객체) 받은 그대로 다음 단계로 넘김
flatMap T Mono 또는 Flux 상자를 까서 알맹이 R만 꺼내 다음 단계로 넘김
flatMapMany T Flux Mono를 여러 개의 알맹이가 흐르는 Flux로 확장함
flatMapIterable T Iterable (List 등) 리스트를 하나씩 쪼개서 순차적으로 내보냄

이 포스팅은 쿠팡 파트너스 및 알리익스프레스 어필리에이트 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *