본문 바로가기
개발/JAVA

모던 자바 인 액션 스터디

by 설이주인 2022. 10. 13.

http://www.yes24.com/Product/Goods/77125987

 

모던 자바 인 액션 - YES24

자바 1.0이 나온 이후 18년을 통틀어 가장 큰 변화가 자바 8 이후 이어지고 있다. 자바 8 이후 모던 자바를 이용하면 기존의 자바 코드 모두 그대로 쓸 수 있으며, 새로운 기능과 문법, 디자인 패턴

www.yes24.com

 

 

 [10.20 - 11.08]


1장  [자바 8 - 11] 까지의 상황에 대하여

메서드를 값으로 전달 한다

스트림의 외부/내부 반복

컬렉션 > 스트림 > 병렬처리 >List + 복원


2장 동작 파라미터화

동작 파라미터화 - 아직 어떻게 실행할지 정의하지 안은 코드 블록을 의미한다.

해당 블록은 나중에 프로그램에서 호출하며 실행은 나중으로 미뤄지는것이다.

책에서는 Apple을 분류하는 방식으로 진행하지만 개인 공부를 위해 따로 코드를 작성했다.

 

package

 

Member
Gender
Predicate

검색 조건 : 나이, 이름 성별로 진행한다.

FilterMember
GetMember

위의 코드에서 Predicate의 객체의 선언하는 이유는 메서드가 객체만 인수로 받기 때문이다.

test의 메서드를 구현하고 불리언 표현식을 전달할 수 있기에 이 동작은 '코드를 전달'할 수 있는 것이나 다름없다.

 

책에서는 동작 파라미터를 사용하는 이유를 변화하는 요구 사항에 잘 대응하기 위해서이라고 한다.

또한 각 항목에 적용할 동작을 분리할 수 있다는게 동작 파라미터화의 강점이다.

 

기존에는 파라미터들을 넘겨서 처리하는 방식으로 진행했었는데 '부모는 자식을 품을 수 있다'를 생각한다면... 분명 맞는 말이다.

다만 아쉬운점은 파라미터로 넘기는 행위가 간소화 되지 않는 코드는 오히려 길게 느껴진다는 부분이다. (어려우면서도 신기하다)

 


3장 람다

람다의 표현식은 익명 클래스와 비슷하며 표현식 전체가 함수형 인터페이스의 인스턴스로 취급된다.

 

위에서는 람다가 인수를 자신의 바디안에서만 사용했지만

자유함수 (파라미터안의 변수가 아닌 외부변수)도 활용할 수 있다. 이 행동을 람다 캡처링이라고 한다.

 

자유함수를 사용할때 제약사항이 존재한다.

사용 하는 변수가 실질적/명시적으로 final 상태이어야 한다는 점이다.

 

+ 메소드 참조

 

기존의 Member를 나이별로 sort 한다.

3장 람다... 보다는 메소드 참조, 그리고 Comperator, Predicate... 유틸들에 조금더 집중한 기분이다...

다른 유틸은 아직 잘 모르겠지만 비교자는 잘 사용할거 같다


4장 스트림 소개

Dish
Type
GetDishes

스트림의 특징을 짧게 보고 넘어가자

- 선언형으로 구현이 가능하다

- 동작 수행으로 처기 가능 (if문 제어 X)

- 요구사항에 대응하기 쉽다.

 

위의 lowCaloriesDishesName을 통해서 우리는 stream이 filter > sorted > map으로 선언 파이프라인 형식으로 되어있음을 확인할 수 있다. 또한 스트림을 통해서 가독성, 유연성, 성능까지 챙길 수 있다.

 

우리가 흔히 생각하는 컬렉션과 스트림의 차이 확인해보자

 

스트림

- '데이터 처리 연산을 위해 소스에서 추출된 연속된 요소'

- filter, sort, map과 같이 표현 계산식이 메인이다.

- 스트림 연산은 파이프라인 형식을 구성할 수 있도록 자기 자신을 반환한다.

- 내부 반복을 지원한다.

- 한 번만 탐색할 수 있다.

- 사용자 요청시에만 요소를 계산한다. 스트림은 게으른 컬렉션이다.

 

컬렉션

- 반복 탐색이 가능하다.

- 외부 반복으로 사용자가 직접 반복자를 붙여줘야 한다. (ex: for-each)

- 자료구조로 시간, 공간의 복잡성 그리고 관련된 요소 저장 및 접근 연산에 집중 되어있다.

- 현재 자료구조가 포함하는 모든 요소들을 저장하며 적극적으로 생성한다.

 

stream, collection

threeHighCaloricDishNames 의 파이프라인 중 < filter, map, limit>까지를 우리는 중간 연산, 그리고 collect은 최종 연산이라고 부른다.

중간 연산의 특징은 단말 연산을 스트림 파이프라인에 실행하기 전까지 아무런 연산을 수행하지 않는다는 것이다.

중간 연산을 다 합친 후 그 연산을 최종 연산으로 한번에 처리한다.

코드를 통해서 확인해보자

stream
threeHighCaloricDishNames log

스트림의 게으른 특성이다. 이를 통해서 우리는 최적화 효과를 얻을 수 있다. 또한 3개만 나온것은 limit연산 (쇼트서킷 기법)이다.

log를 통해서 알 수 있듯이 filter, map은 현재 하나의 과정으로 병합되었으며 이를 루프 퓨전이라고 한다.

 


5장 스트림 활용

4장에 이어서 스트림에서 활용하는 API들을 소개한다.

 

기본&nbsp; filter

takeWhile, dropWhile

takeWhile, dropWhile

limit

limit

skip

skip

map, flatMap 

map, flatMap

reduce 연산 : 스트림 모든 요소를 처리해서 값으로 도출하는 작업

reduce

range, rangeClosed

 

현재 flatMap의 상용 방법이 제일 헷갈리는 상황이다.. 따로 정리해야겠다.

+) 

https://winter1396love.tistory.com/66

 

자바 flatMap 이해하기

자바 Stream API에서 map 사용은 익숙하지만 flatMap은 조금 생소한 상황이다. flatMap을 스트림 평면화로 설명해준다. 설명만으로 이해가 어렵기에 코드로 보는걸로 1차 배열 2차 배열 중복 구조로 되어

winter1396love.tistory.com


6장 스트림 데이터 수집

toList List<T> 스트림의 모든 항목을 리스트로 수집
toSet
Set<T>
스트림의 모든 항목을 집합으로 수집
toCollection
Collection<T>
스트림의 모든 항목을 발행자가 제공하는 컬렉션으로 수집
counting
Long
스트림 항목 수 계산
summingInt
Integer
스트림 항목의 정수 프로퍼티 값 더함
averagingInt
Double
스트림 항목의 정수 프로퍼티 평균값 계산
summarizingInt
IntSummaryStatistics
최댓값, 최솟값, 합계, 평균 등의 정수 정보 통계 수집
joining
String
스트림 각 항목에 toString 메서드를 호출한 결과 문자열 연결
maxBy
Optional<T>
최댓값 요소를 Optaionl로 감싼 값으로 반환. 요소가 없을때는 Optional.empty()반환
minBy
Optional<T>
최소값 요소를 Optaionl로 감싼 값으로 반환. 요소가 없을때는 Optional.empty()반환
reducing
produced by the reduction operation
누적자를 초깃값으로 설정한 다음에 BinaryOperator로 스트림의 각 요소를 반복적으로 누적자와 합쳐 스트림을 하나의 값으로 리듀싱
collectingAndThen
returned by transforming function
다른 컬렉터를 감싸고 그 결과에 변환 함수 적용
groupingBy
Map<K, List<T>>
하나의 프로퍼티값을 기준으로 스트림의 항목을 그룹화하여 기준 프로퍼티값을 키로 사용
partitionBy
Map<Boolean, List<T>>
Predicate를 스트림의 각 항목에 적용한 결과로 항목 분할

 

summingInt

summarizingInt

 

 

joining

 

groupingBy

- 스트림 요소를 하느이 값으로 리듀스, 요약
- 요소 그룹화
- 요소 분할
- 연산을 바킷 (BUCKET)에 담는다고 생각하면 편하다

 

 

 

 

 

 

 

partitionBy - 불린 반환, flase/true 두 요소 모두 유지

 

 


8장  컬렉션 API

Collection의 remove 동작으로 발생한 에러 UnsupportedOperationException을 보고 넘어가자

우선 removeIf()로 List내의 mick를 제거하고자 삭성한 코드이다. 

우릐 코드로 발생한 에러

지원하지 않은 방식이라고 한다... 그럼 인텔리제이에서 주는 힌트를 적용해서 재시도 해보자

기존List를 ArrayList로 감싸고 실행해보자

성공이다.

 

List.of를 조금 더 탐구해보자

해당 메소드 설명에서 우리는 아래의 설명을 확인할 수 있다.

위와 같이 Elements cannot br added, removed or replace라고 명시 되어있다.

 

replaceAll

 

forEach,

comparingByValue,

comparingByKey,

getOrDefault

 

compute :  제공된 키로 새 값을 계산하고 맵에 저장한다.

computeIfAbsent : 제공된 키가 없으면 compute 실행

computeIfPresent : 제공된 키가 있으면 compute 실행

putAll : 중복 없을시

merge : 중복 있으면 유연하게 매칭 됨

 

ConcurrentHashMap :  동시성 친화적, 내부 자료구조의 특정 부분만 잠궈서 동시 추가, 갱신 작업을 허용한다.

해당 ConcurrentHashMap은 세가지 연산을 지원한다.

키, 값으로 연산 forEach, reduce, search
키로 연산 forEachKey, reduceKey, searchKey
값으로 연산 forEachValue, reduceValues, searchValues
Map, Entry 객체로 연산 forEachEntry, reduceEntries, searchEntries

해당 HashMap의 상태를 잠그지 않고 연산을 수행한다는 점에서 계산이 진행되는 동안 바뀔 수 있는 객체, 값, 순서 등에 의존해서는 안된다.

연산의 병렬성 기준값도 지정해야한다.

ConcurrentHashMap은 매핑 개수를 반환하는 mappingCount, 집합뷰를 반환하는 keySet 메서드를 제공한다.

+) ConcurrentHashMap는 아래 링크를 추가로 확인하자.

https://pplenty.tistory.com/17

 

[java] ConcurrentHashMap 동기화 방식

java8 (jdk 1.8.0_162) 기준으로 작성하였다. 기본적인 동작은 HashMap 과 동일하거나 비슷한 부분이 많아, HashMap 의 동작 원리 를 먼저 알아야 이해하기가 수월하다. HashMap 은 멀티스레드 환경에서 동시

pplenty.tistory.com


9장 [리팩터링,테스팅, 디버깅]

10장 [람다를 이용한 도메인 전용 언어]

 

두 챕터는 람다를 이용한 리팩토링, DSL을 이야기한다.

람다 표현식으로 불필요한 코드 제거가 가능한 점

DSL의 주요 기능은 개발자와 도메인 전문가의 간격을 좁히는것에 있다

자바에서는 Stream, Collectors과 같은 정렬, 필터링, 변환, 그룹화에 유능한 API를 제공한다.

자바 SQL mapping 도구 jOOQ, BDD 프레임워크 큐컴버, 엔터프라이즈 등 스프링 확장도 존재한다.

 

개인적으로 리펙토링으로 람다 형식으로 많은 코드를 변경하면서 개발자 보기 편한 방향으로 바꾼다만 알고 있었는데

이 행위가 DSL과도 관계가 있다는 점에서 좀 신기했다,,!

 


11장 null 대신 Optional 클래스

개발을 하면서 제일 흔하게 마주하는 에러를 고르자면 NullPointerException을 생각할 수 있다.
 
null은 우리에게 다양한 문제를 발생시킨다.
- NullPointerException
- 코드의 가독성이 떨어진다.
- null은 아무 의미가 없다
- null은 무형식이며 정보를 포함하고 있지 않아서 모든 참조 형식에 null을 할당할 수 있다.

위의 null을 방지하기 위해서 Optional 클래스가 존재한다.
 
Optional은 선택형값을 캡슐화하는 클래스이다.  값이 있으면 Optional 클래스는 값을 감싸고 값이 없으면 Optional.empty로 Optional 객체를 반환한다.

그럼 우리가 조심해야하는 null과 Optional.empty의 차이는무엇일까?

null을 참조하는 것은 NullPointerException으로 이어지지만 Optional.empty()는 Optional 객체이다.

우리는 Optional을 사용함으로서 값이 없는 상황인지, 데이터에 문제가 존재하는지 또는 알고리즘의 문제인지 상황을 명확히할 수 있다.

하지만 모든 null에 Optional을 적용하는 것은 바람직하지 않다.
 
Optional의 역할은 더 이해하기 쉬운 API를 설계하도록 돕는 역할이다. 코드만 보고 사람이 해당 메소드가 어떠한 부분을 진행하며 결과로 어떤 부분을 돌려주는지 이해를 도와준다.

또한 Optional로 해당 API를 언랩해서 값이 없을 수 있는 상황에 적절하게 대응하도록 강제하는 효과가 있다.
Optional에서 제공하는 API 목록들이다.
Optional
        .get (가장 위험함)
        .orElse
        .orElseGet
        .orElseThrow
        .ifPresent
        .ifPresentOrElse
        .empty
        .filter
        .flatMap
        .map
        .stream
        .ofNullable

Optional에도 기본형들이 존재하지만 기본형들로 성능개선을 기대하는것은 어렵다고 한다.
 
개인적으로 Optional을 통해서 try/catch 로직을 피해갈 수 있고, null safe한 부분이 매우 매력적이라고 생각한다.

12장 날짜와 시간 API

JAVA  유틸에서 제공해주는 클래스가 존재한다.

LocalDate, LocalTime, LocalDateTime, Instant, Duration, Period

 

Instant는 기계의 날짜를 계산하며 초와 나노초 정보를 제공하기에 사람이 읽을 수 있는 정보를 제공하지 않는다.

Duration은 초와 나노초로 시간 단위를 표현하기에 between 메서드에 LocalDate 정보 전달이 불가능하다.

그래서 Period로 처리한다.

메서드 정적 설명
between Y 두 시간 사이의 간격 생성
from Y 시간 단위로 간격 생성
of Y 주어진 구성 요소에서 간격 인스턴스 생성
parse Y 문자열 파싱, 간격 인스턴스 생성
addTo N 현재값의 본사본 생성 후 다음에 지정된
Temporal 객체에 추가함
get N 현재 간격 정보값을 읽음
isNegative N 간격이 음수인지 확인
isZero N 간격이 0인지 확인
minus N 현재값에서 주어진 시간을 뺀 복사본을 생성함
multipliedBy N 현재값에서 주어진 값을 곱한 복사본을 생성함
negated N 주어진 값의 부호를 반전한 복사본 생성
plus N 현재값에 주어진 시간을 더한 복사본 생성
substractFrom N 저장된 Temporal 객체에서 간격을 뺌

 

우리가 LocalDate에서 특정 날짜에 조작이 필요한 경우

메서드 정적 설명
from Y 주어진 Temporal 객체를 이용해서 클래스의 인스턴스를 생성함
now Y 시스템 시계로 Temporal 객체 생성
of Y 주어진 구성요소에서 Temporal 객체의 인스턴스를 생성함
parse Y 문자열을 파싱해서 Temporal 객체 생성 
atOffSet N 시간대 오프셋과 Temporal 객체 합침
atZone N 시간대 오프셋과 Temporal 객체 합침
format N 지정된 포맷으로 Temporal 객체를 문자열로 변환함
get N Temporal 객체 상태를 읽음
minus N 특정 시간을 뺀 Temporal을 생성
plus N 특정 시간을 더한 Temporal을 생성
with N 일부 상태를 바꾼 Temporal을 생성

위의 상황은 간단한 3일 더하기 1년빼기와 같은 동작들이다. 만약에 다음주 일요일, 돌아오는 평일 또는 특정 달의 마지막 날을 구하고 싶을때는 어떻게 처리 할까?

TemporalAdjusters를 사용해주자

 

메서드 설명
dayOfWeekInMonth 서수 요일에 해당하는 날짜를 반환
firstDayOfMonth 현재 달의 첫 번째 날짜를 반환
firstDayOfNextMonth 다음 달의 첫 번째 날짜를 반환
firstDayOfNextYear 내년의 첫 번째 날짜를 반환
firstDayOfYear 올해의 첫 번째 날짜를 반환
firstInMonth 현재 달의 첫 번째 요일 날짜를 반환
lastDayOfNextMonth 현재 달의 마지막 날짜 반환
lastDayOfNextYear 올해의 마지막 날짜를 반환
lastInMonth 현재 달의 마지막 요일 날짜 반환
next previous 현재 달에서 현재 날짜 이후로 지정한 요일이 처음으로 나타나는 날짜 반환
nextOrSame 현재 날짜 이후로 지정한 요일이 처음/이전으로 나타나는 날짜 반환
previousOrSame 현재 날짜 포함 반환

DateTimeFormatter

 

특정 Formatter을 만들고 싶다면 DateTimeFormatterBuilder을 이용하면 된다.


13장 디폴트 메세지

인터페이스를 정의하는 두 가지 방법이 존재한다.

1. 인터페이스 내부에 있는 정적 메소드를 사용

2. 디폴트 메소드를 사용

 

그럼 default, 정적 메서드는 무엇일까?

 

아래의 코드에서 sort는 디폴트, naturalOrder()은 새로 추가된 정적 메소드다.

 

우리는 보통 인터페이스 그리고 해당 인터페이스를 활용할 수 있게 정의된 유틸리티 클래스를 주로 사용한다.

 

우리가 자주 사용하는 Collections는 Collection 객체를 활용할 수 있는 유틸리티 클래스이다.

 

보통 공개된 인터페이스에 추상 메소드를 추가하면 호환성이 깨지는 상황이 발생한다.

ERROR : AbstractMethodError : setRelativeSize()

 

디폴트 메세지 덕분에 라이브러리 설계자가 API를 바꿔도 기존 버전과 호환성을 유지할 수 있다.

 

클래스 또는 인터페이스로부터 같은 시그니처를 갖는 메소드를 상속 받을 시 주의할 점이 존재한다.

 

1. 클래스가 우선 순위가 가장 높다. 디폴트 메소드 보다 높은 우선 순위를 갖는다.
2. 1번외의 상황에서는 서브 인터페이스의 우선 순위가 높다. B가 A를 상속 받느면 B가 A보다 우선 순위가 높다.
3. 우선 순위가 정해지지 않았다면 여러 인터페이스를 상속받는 클래스가 명시적으로 디폴트 메서드를 오버라이드하고 어떤 디폴트 메세지를 호출할지 결정해야한다.

 


16장 안정적 비동기 프로그래밍

우선 동기 API와 비동기 API의 차이로 시작하자

 

동기 API는 메서드 호출 후 해당 메서드가 완료될 때까지 기다렸다가 메서드가 반환되면 그 다음 동작을 실행한다. 호출자와 피호출자가 다른 스레드에서 작업을 하고 있어도 호출자는 피호출자의 동작 완료를 기다려야한다. 이와 같은 상황을 블록 호출이라고 한다.

 

비동기 API는 메서드가 즉시 반환되며 끝내지 못한 작업은 호출자 스레드와 동기적으로 실행될 수 있도록 다른 스레드에 할당한다.

이런 상황을 비블록 호출이라고 한다. 다른 스레드에서 작업한 결과값을 콜백 메서드를 호출해서 전달하거나 호출자가 '계산 결과가 끝날때까지 기다린다'의 메서드를 호출하면서 전달 된다. 

 

해당 장에서 중점을 보는 메서드는 CompletableFutureFuture이다.

Future은 미래의 어느 시점에 결과를 얻는 모델에 활용할 수 있는 인터페이스이다. 계산이 끝났을때 결과에 접근할 수 있는 참조를 제공한다. Future을 사용하면서 시간이 오래 걸리는 작업을 Callable 객체 내부로 감싼 다음에 ExcutorService에 제출해야한다.
또한 Future에는 isDone, 계산이 끝나기를 기다리는 메서드, 결과 회수 메서드 등을 제공한다. 하지만 우리는 A 동작 후 결과를 조회, 그 결과 값으로 B동작 그리고 그 결과 값을 보는 이런 동작을 Future로 구현하는 것을 쉽지 않다. 이런 부분은 CompletableFuture을 사용한다.

 


코드로 확인해보자

 

FutureCompletableFuture로 변경하면

위와 같은 형식으로 변경할 수 있다. supplyAsync는 Supplier을 인수로 받아서 CompletableFuture을 돌려준다.

이 상황에서 CompletableFuture은 결과를 비동기적으로 산출해준다.

 

비블록 코드를 확인해보자.

직렬 동기로 코드를 처리하면 아래와 같은 시간이 소요 된다.

 

코드를 병렬처리 동기로 바꿔보자

단축이 가능하다. 그럼 CompletableFuture으로 코드를 수정해보자

더보기

위의 코드에 대해서 작은 설명을 첨부한다.

 

shop -> CompletableFuture.supplyAsync(
        () -> shop.getName() + " price is " + shop.getPrice(product))

CompletableFutures로 각각의 가격을 비동기적으로 계산한다.

return priceFutures.stream().map(CompletableFuture::join)

return 구간에서 모든 비동기 동작이 마무리 되기를 기다린다. CompletableFurture은 기존 작업 요청이 완료 되어야 join이 결과를 반환하고 다음 상점 정보를 요청하는 코드다.

 

그럼 우리는 당연하게 의문점 하나가 발생한다. Stream을 왜 둘로 나눠서 실행한것인가?

 

한 스트림으로 처리하면 스트림의 게으른 특성으로 인해 비동기 처리가 아닌 동기 그리고 순차적으로 코드가 진행되어버린다.

결과에 큰 변화는 없다.

 

그럼 조금 더 개선을 해보자. 4개의 스레드로 4개의 작업을 한번에 병렬로 처리한다면?

 

우리는 커스텀 Executor을 사용해볼것이다.

너무 만은 스레드는 서버에 무리를 준다. 사용할 최대 스레드는 100개 이하로 설정하자.

 

... (중간의 Executor은 다시 보는 것으로...)

 

Future을 사용할때의 주의점은 무한정 기다리는 상화잉 발생할 수 있는 점이다. 이런 상황에서는 Completablefuture에서 제공해주는

.orTimeout 메서드를 이용하자

 


17장 리액티브 프로그래밍

리액티브 프로그래밍은 다양한 시스템과 소스에서 들어오는 데이터 항목 스트림을 비동기적으로 처리하고 합쳐서 이런 문제를 해결한다.

위와 같은 처리 방식으로 사용자에게 높은 응답성, 애플리케이션 소장, 정전 같은 상태에 대한 대처, 그리고 다양한 네트워크 상태에서 메세지를 교환하고 전달할 수 있으며 무거운 작업을 하는 상황에서도 가용성을 제공한다.

 

리액티브 프로그래밍의 핵심 원칙은

반응성 : 일정하고 예상 가능한 반응시간을 제공

회복성 : 장애가 발생하더라도 시스템은 반응해야한다.

탄력성 : 무거운 작업 부하가 발생하면 자동으로 관련 컴포넌트에 할당된 자원수를 늘린다.

메세지 주도 : 회복성과 탄력성을 지원하기 위해서는 약한 결합, 고립, 위치 투명성 등을 지원할 수 있게 컴포넌트의 경계를 명확하게 정의해야한다. 컴포넌트는 비동기 메세지 전달해 컴포넌트끼리의 통신이 이뤄진다. 이 덕분에 회복성, 탄력성을 얻을 수 있다.

 

우리가 제일 중점으로 볼것은 비동기로 작업을 수행한다는 점이다.

 

애플리케이션 수준 리액티브 프로그래밍

시스템 수준의 리액티브

리액티브 스트림과 플로 API

 

Flow

리액티브 프로젝트의 표준에 따라 프로그래밍 발행 - 구독 모델을 지원할 수 있다.

- Publisher

- Subscriber

- Subscription

- Processor

 

Publisher이 항목을 발행하면 Subscriber은 한 개씩 또는 한 번에 여러 항목을 소비한다. 이때 Subscription이 이 과정을 관리할 수 있도록 Flow 클래스는 관련된 인터페이스와 정적 메서드를 제공하고 있다. Publisher은 수많은 이벤트를 발행할 수 있지만 subscriber의 요구사하에 따라 역압력 기법으로 인해 이벤트 제공 속도가 제한된다.

 

Publisher을 살짝 살펴보자

 

Subscriber

Subscription에서는 항상 onSubscribe가 첫번째로 호출 된다. 그 이후 여러 onNext가 여러 번 호출 될수 있다.

이벤트 스트림은 지속되거나 onComplete 콜백을 통해서 더이상 데이터가 없고 종료 되었다는것을 알 수 있으며 Publisher에서 에러가 발생하면 onError를 호출한다.

 

onSubscribe 안의 Subscription을 살펴보자

 

Subscription

 

이들 인터페이스 구현이 어떻게 서로 협력해야 하는지의 규칙은 아래를 살펴보자

- Publisher은 반드시 Subscription의 request 메서드에 정의된 개수 이하의 요소만 Subscriber에 전달해야 한다.

- Subscriber는 요소를 받아 처리할 수 있음을 Publisher에 알려야 한다. 이 방법으로 Subscriber는 Publisher에 역압력을 행사할 수 있고 Subscriber가 관리할 수 없는 양을 받는 일을 피할 수 있다. 그리고 마지막까지 Subscription.cancel()이 호출된 이후라고 한 개 이상의 onNext를 받을 준비가 되어있어야한다.

- Publisher과 Subscriber는 정확하게 Subscription을 공유해야하며 각각의 역할을 수행해야 한다. 이를 위해서는 onSubscribe, onNext 메서드에서 Subscriber는 request 메서드를 동기적으로 호출할 수 있어야 한다. 규칙에서는 Subscription.cancel() 메서드는 몇 번을 호출해도 한 번 호출하는것과 같은 효과를 가져야한다. 하나의 호출이 다른 호출에 영향을 주지 않도록 스레드 세이프여야한다.

 

 

TempInfo
TempSubscription
TempSubscriber

 

RxJava

+) 사용 방법은 아래 깃을 참고하자

https://github.com/ReactiveX/RxJava

 

GitHub - ReactiveX/RxJava: RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based p

RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM. - GitHub - ReactiveX/RxJava: RxJava – Reactive E...

github.com

 

Observable에는 just메서드, interval메서드가 존재한다

just() : 메서드는 한개 이상의 요소를 이용해 이를 방출하는 Observable로 변환한다.

아래 코드는 onNext("first") > onNext("second") > onComplete 로 진행된다.

Observable<String> strings = Observable.just("first", "second");

interval() : interval은 onePerSec의 변수로 Observable을 반환해 할당한다.

Long 1의 값을 무한으로 증가 시키며 값을 방출한다.

Observable<Long> onePerSec = Observable.interval(1, TimeUnit.SECONDS);

 

RxJava에서 Observable이 플로 API의 Publisher 역할을 하며 Observer는 Flow의 Subscriber 인터페이스 역할을 한다.

Observable은 역압력을 지원하지 않으므로 Subscription의 request메서드를 포함하지 않는다.

 

Observer을 살펴보자

 

Observable, Emitter을 살펴보자

 

RxJava는 플로 API보다 유연한 편이다.

RxJava, 리액티브 리이브러리는  스트림을 합치고 만들고 다양한 방법을 제공한다.

filter, map ...

 


 

깃 주소 : https://github.com/EssLemint/modernjavainaction

 

 

 

 

 

 

 

 

 

 

 

 

'개발 > JAVA' 카테고리의 다른 글

DTO에서 @Setter쓰는 것에 대한 주저리[1]  (0) 2023.09.17
자바 flatMap 이해하기  (0) 2022.11.03
@NoArgsConstructor(access = PROTECTED)에 관하여  (0) 2022.09.12
ModelMapper와 친해지기  (0) 2022.07.14
Iterator  (0) 2022.07.11