구글 클라우드 플랫폼(GCP)를 사용하려면 먼저 계정을 등록시켜야 합니다. Gmail에 사용하는 구글 계정이 있는경우 이를 통해 로그인을 진행 할 수 있지만 클라우드 계정이 없다면 클라우드 계정에 가입해야합니다. 구글 클라우드 플랫폼은 90일간 $300을 사용할 수 있는 무료 크레딧을 제공해 주기 때문에 이를 통해 구글 클라우드 플랫폼을 체험해 볼수도 있습니다.
구글 클라우드 플랫폼 등록을 맞추면 클라우드 콘솔로 이동하고 My First Project라는 새로운 프로젝트가 자동으로 만들어 줍니다. 또한 페이지의 왼편에는 컴퓨팅, 서버리스, 저장소등과 같이 구글 클라우드 플랫폼이 제공하는 서비스가 속한 카테고리와 프로젝트별 구성란이 있습니다.
1. 프로젝트 선택하기
2. cloud shell
cloud shell 활성화하기
cloud shell 로 한 프로젝트에 속한 application 들을 관리
gcloud auth list
gcloud config set account `이메일계정`
다음과 같이 output 이 나오면 인증 되었고, 아래 명령어로 프로젝트를 확인하면 된다.
사용하고 있는 쉘의 종류에 따라 파일을 변경해준다. (.bashrc, .bash_profile, .zshenv 등등)
# bash 환경변수 파일 열기
vi ~/.bash_profile
or
# zsh 환경변수 파일 열기
vi ~/.zshrc
아래 코드를 붙여넣기 하고 저장한다. (:wq)
# ~/.bash_profile 설정
export NVM_DIR="$HOME/.nvm"
[ -s "/usr/local/opt/nvm/nvm.sh" ] && . "/usr/local/opt/nvm/nvm.sh" # This loads nvm
[ -s "/usr/local/opt/nvm/etc/bash_completion" ] && . "/usr/local/opt/nvm/etc/bash_completion" # This loads nvm bash_completion
# ~/.zshrc 설정
export NVM_DIR=~/.nvm
source $(brew --prefix nvm)/nvm.sh
source명령어로 저장한 코드를 적용시켜준다.
# bash 적용
$ source ~/.bash_profile
or
# zsh 적용
$ source ~/.zshrc
5. nvm 확인
$ nvm -v
0.39.3
nvm 으로 node 설치하기
노드 버전 설치하기
install명령어를 사용해 특정 노드 버전을 설치할 수 있다.
nvm install v14.18.1
만약lts버전(서버환경에서 장기적으로 안정적 지원을 제공하는 버전)를 설치하고 싶다면, 아래 명령어를 사용하자.
nvm install --lts
설치된 노드 목록 보기
만약 설치된 node 버전을 보고 싶다면nvm ls
nvm 명령어 목록
# node의 리스트 확인
nvm ls
# node 설치 : install 뒤에 node 버전 입력
nvm install 17.5.0
# node 사용 : node에 대해 nvm을 이용하여 등록 처리
nvm use 17.5.0
# 특정 node 버전 삭제
nvm uninstall 17.5.0
# 여러버전의 node중에 어떤것으로 사용할 지 default 버전 설정
nvm alias default v12.18.2
# node 버전 확인
node --version
or
node -v
Pagination 기능을 편리하게 사용할 수 있도록 JPA는 Pageable이라는 객체를 제공한다.
controller 에서 부터 pageable 관련 파라미터를 받을 수 있다.
정렬 기능
@GetMapping("/")
public ResponseEntity getData(
@PageableDefault(size = 10, sort = "reqDt", direction= Sort.Direction.DESC)
Pageable pageable)
// reqDt 에 대한 내림차순 정렬
@SortDefault
위의 방식은 정렬을 한가지만 할 수 있어, 여러 정렬 조건을 추가하려면 @SortDefault 를 추가하면 된다.
@GetMapping("/")
public ResponseEntity getData(
@SortDefault.SortDefaults({
@SortDefault(sort = "id", direction = Sort.Direction.ASC),
@SortDefault(sort = "reqDt", direction = Sort.Direction.DESC)
})
@PageableDefault(size = 10)
Pageable pageable)
// id 오름차순 및 reqDt 에 대한 내림차순 정렬
controller 요청방법
?page=0&size=10&sort=regDt,desc
PageRequest
다른 방법으로는 controller 에서 외에 paging 관련 데이터를 PageRequset 객체에 넣어 Pagable 을 생성 후 find 쿼리 메소드에 객체를 전달하면 된다.
챗GPT 의 사전 지식부터 챗GPT 서비스에 대한 종류들 그리고 챗GPT 의 등장으로 인한 여러 변화들과
api 를 사용하는 방법 등등 그리고 챗GPT 를 활용하는 방법까지 이 책은 소개 하고 있어서 개발자부터 비개발자 전부 이 책을 활용 할 수 있을 것 같아 범용적인 책으로 소개하고 싶다.
하지만 아무래도 컴퓨터 관련 전공자가 책을 읽기 조금 수월하다.
아래는 전체적인 내용을 요약한 개요다.
[챗GPT 개념과 동작 원리 이해] ㆍ 임베딩, 인코딩, 디코딩, 자연어 처리 개념 ㆍ 자연어 처리 알고리즘과 챗GPT 동작 원리
[다양한 챗GPT 서비스 소개] ㆍ 챗GPT 플러그인, GPT-4 모델 ㆍ 달리, 코덱스, 위스퍼, 빙, 코파일럿, 루프
[챗GPT 직접 사용해보기] ㆍ 챗GPT 가입하고 질문하기 ㆍ API 키 획득, 퓨샷, 원샷, 제로샷 러닝 ㆍ 파인 튜닝, GPT-3 API 사용, 챗GPT API 사용 ㆍ 위스퍼 사용, 애저에서 챗GPT 사용
[챗GPT 활용 시나리오] ㆍ 챗GPT 유스케이스, 코딩하기, 이미지 생성 ㆍ 업무에 활용: 업무 관련 질문, 엑셀에서 사용 ㆍ 일상생활 질문: 전등 교체나 요리법 등 ㆍ 과제하기, 챗GPT로 작성한 과제 찾기
아래는 챕터 내용이다.
1부. 알아 두면 쓸모 있는 사전 지식
1장. 자연어 처리, 일상생활의 언어를 이해하여 분석하다 자연어 처리를 이해하기 위해 미리 알아 두자 __단어를 수치로 표현하다: 임베딩 __컴퓨터와 인간에게 맞는 표현으로 변환한다: 인코딩과 디코딩 __자연어 처리란? 자연어 처리를 효율적으로: 자연어 처리 알고리즘 __순환신경망(RNN) __순환신경망 장단기 기억(LSTM) __seq2seq와 어텐션 __트랜스포머, 버트, GPT 생성형 언어 모델, 챗GPT
2부. 챗GPT, 베일을 벗다
2장. 챗GPT가 궁금해? 챗GPT, 너의 정체가 궁금하다 __새로운 셀럽의 등장, 챗GPT __챗GPT의 성과 __챗GPT의 동작 원리 챗GPT 플러그인 GPT-4의 등장 __GPT-4 모델 챗GPT의 형제들 __GPT-3 서비스 __달리(DALL-E) 서비스 __코덱스(Codex) 서비스 __위스퍼(Whisper) 서비스 GPT의 발전 과정
3장. 챗GPT의 등장으로 인한 변화 챗GPT의 등장과 구글의 종말 챗GPT에게 도전장을 내밀다 책임 있는 AI란? 챗GPT의 진실과 거짓 챗GPT의 한계
4장. 오픈AI와 마이크로소프트 오픈AI와 마이크로소프트의 관계 __마이크로소프트의 12조 원 투자 __오픈AI의 챗GPT와 마이크로소프트의 챗GPT 마이크로소프트 빙 마이크로소프트 코파일럿 마이크로소프트 루프
3부. 챗GPT 시작하기, 파인 튜닝과 API
5장. 챗GPT 만들기 챗GPT 시작하기 __챗GPT에 질문하기 __오픈AI에서 발급하는 API 키 획득하기 __애저에서 챗GPT를 사용하기 위한 준비 우리 기업만의 챗GPT를 위한 학습 __퓨샷, 원샷, 제로샷 러닝 __퓨샷, 원샷 러닝을 사용하기 위한 구성 파인 튜닝 챗GPT API는 어떻게 사용할까? __GPT-3 API 사용하기 __GPT-3 파인 튜닝 __챗GPT API 사용하기 __위스퍼 사용하기 __애저에서 챗GPT 사용하기
4부. 글쓰기부터 코딩까지, 다양한 챗GPT 활용
6장. 챗GPT 활용하기 챗GPT를 사용하기 위한 유스케이스 업무에 챗GPT 활용하기 __물어볼 곳이 없다? 챗GPT에게 물어보자 __엑셀에서도 챗GPT를 사용할 수 있다고? 코딩, 참 쉽죠? 캐릭터도 인공지능으로 뚝딱! 고립인 듯 고립 아닌 삶 교사는 챗GPT가 싫다 __챗GPT로 과제하기 __챗GPT로 작성한 과제 찾아내기
전문지식을 함께 전달하기에 일반인이 읽기에 낯선 용어들이 등장하기도 하지만 깔끔한 편집과 그림을 활용한 설명이 많아 어려운 부분은 천천히 읽다 보면 이해를 할 수 있었고 깊이 있는 지식을 익힐 수 있어 좋다.
특히, 4부의 활용부분에서는 엑셀, 코딩 등 직접 활용할 수 있는 실제 활용법을 따라 해볼 수 있도록 자료를 통해 설명하고 있어 큰 도움이 된다.
총 4부로 구성된 이 책은 알아 두면 쓸모 있는 사전 지식, 챗GPT 베일을 벗다, 챗GPT 시작하기, 파인 튜닝과 API, 글쓰기부터 코딩까지 다양한 챗GPT 활용으로 나뉘어 세세하고 깊이 있는 정보를 알차게 전달하고 있다.
자연어 처리를 이해하기 위한 몇 가지 개념을 익히고 자연어 처리와 챗GPT에 대한 설명, 챗GPT의 개념과 동작 원리를 이해하고 GPT-4에 대한 정보, GPT-3, 달리, 코덱스, 위스퍼, GPT의 발전 과정, 챗GPT 등장으로 인한 변화와 챗GPT를 둘러싼 소문의 진위여부, 한계점, 오픈 AI와 마이크로소프트, 챗GPT의 활용, 챗GPT를 만들기 위한 챗GPT API와 파인 튜닝 등 챗GPT와 관련된 모든 정보를 한 권으로 차근히 배울 수 있다.
그렇다면 왜 이를 위한 별도의 클래스가 필요한 걸까요? 맞습니다. 하지만 아래 코드를 살펴보세요.
String country = student.getStudentDetails().getAddress().getCountry().toLowerCase();
switch(country) {
case "India":
// 뭔가를 수행합니다
case "USA":
// 뭔가를 수행합니다
// 다른 나라들
}
위 예제는 student, studentDetails, address 또는 country 객체 중 하나라도 null이라면 NullPointerException의 가능성이 여러 곳에서 발생할 수 있습니다.
이제 여러분은 이전처럼 null 체크를 추가하고 싶을지도 모릅니다. 그러나 그렇게 한다면 위 코드는 다음과 같이 변합니다.
보시는 대로 이 코드는 읽기 어렵고 유지 및 수정하기도 어렵습니다. 이러한 문제를 해결하기 위해 Optional이 만들어졌으며, Optional에 대해 자세히 학습한 후에 다시 살펴보겠습니다.
Optional이란? Optional은 객체 위에 래퍼 또는 컨테이너입니다. 값(또는 객체)을 포함할 수도 있고 포함하지 않을 수도 있습니다. Optional은 어떤 객체든 포함할 수 있으므로 Optional<String>, Optional<Cat> 등의 형식으로 선언되며 아래와 같이 생겼습니다.
Optional을 사용하면 값이 존재할 때만 해당 값을 가져오거나, 보유하는 객체가 없거나 null인 경우 기본값을 반환할 수 있습니다.
이를 통해 NullPointerPointerException 문제를 해결하며 코드를 기존의 null 체크보다 더 읽기 쉽게 만듭니다. Optional을 깊게 학습한 후에 위의 예제를 Optional 객체를 사용하여 어떻게 수정할 수 있는지 살펴보겠습니다.
Optional 객체 생성 Optional 객체는 생성자를 통해 생성할 수 없습니다. 이는 생성자가 private이기 때문입니다. Optional 객체는 정적 메서드를 사용하여만 생성할 수 있으며 아래에 설명된대로 생성됩니다.
1. of() 메서드 사용 Optional은 Optional.of() 메서드를 호출하여 해당 Optional이 보유할 객체를 제공하여 생성할 수 있습니다. 예제,
Student student = new Student(); Optional<Student> optional = Optional.of(student); 만약 of에 제공된 객체가 null이면 NullPointerException이 발생합니다. 객체가 null일 가능성이 있는 경우에는 다음에 설명하는 메서드를 사용하세요.
2. ofNullable() 메서드 사용 이것은 Optional 객체를 생성하는 두 번째 방법입니다. ofNullable()도 정적 메서드이며 인수로 객체를 받아 이 객체를 포함하는 Optional을 생성합니다.
만약 객체가 null이라면 빈 Optional 객체를 생성하고 반환합니다. 예제,
Student student = new Student(); Optional<Student> optional = Optional.ofNullable(student);
3. 빈 optional 객체 생성 아래와 같이 정적 빈 메소드를 사용하여 빈 값을 가진 Optional 객체를 생성하는 것도 가능합니다.
즉 Optional<String>, Optional<Shape>, Optional<Object>
Value of Optional 앞에서 설명한 것처럼 Optional은 객체를 둘러싼 래퍼이지만 기본 객체에 어떻게 액세스합니까? Optional은 래핑하는 객체를 반환하는 get 메소드를 제공합니다. 이 객체의 유형은 Optional 유형과 동일합니다.
String color = "red";
Optional<String> optional = Optional.of(color);
String back = optional.get();
System.out.print("Color is : " + back);
결과
Color is : red
Check Optional value Optional 객체에 값이 포함되어 있지 않은 경우, 즉 그것이 empty() 또는 ofNullable() 메서드를 사용하여 생성된 빈 Optional이고 get()을 사용하여 해당 값에 액세스하려고 하면 오류가 발생합니다.
Exception in thread “main” java.util.NoSuchElementException: No value present
이 오류를 방지하려면 isPresent() 또는 isEmpty() 메서드를 사용하여 Optional에 액세스하기 전에 Optional에 값이 포함되어 있는지 확인하는 것이 좋습니다. isPresent() 이 메서드는 Optional에 값이 포함되어 있으면 true를 반환하고 그렇지 않으면 false를 반환합니다.
isEmpty() 이 메소드는 isPresent()와 반대로 작동하며 Optional 객체에 값이 없으면 true를 반환하고 그렇지 않으면 false를 반환합니다.
// create empty Optional value
Optional<String> optional = Optional.empty();
System.out.print("Optional contains a value? " + optional.isEmpty());
결과
Optional contains a value? true
Action on value present 마지막 섹션에서는 Optional에 값이 포함되어 있는지 확인하는 방법을 살펴보았습니다. Optional에 값이 포함된 경우 일부 작업을 수행하려면 다음 줄을 생각해 보세요.
Optional<String> o = Optional.empty();
// check if optional contains a value
if(o.isPresent()) {
System.out.print(o.get());
}
그러나 Optional은 if 조건이 필요하지 않은 단축 방법을 제공합니다.
Optional의 isPresent() 메소드를 사용합니다.
이 메소드는 기능적 인터페이스인 java.util.function.Consumer 유형의 인수를 허용하므로 해당 구현을 Lambda 표현식으로 직접 제공할 수 있습니다.
Optional<String> o = Optional.of("Learning optional");
// print value of optional if non-empty
o.ifPresent((e) -> System.out.println(o.get()));
결과
Learning optional
Default optional value 위의 예는 Optional에 값이 있는 경우 취해야 할 조치와 값이 없는 경우 취해야 할 조치를 보여줍니다. Optional은 비어 있는 경우 일부 작업을 수행하는 방법을 제공합니다. 이러한 방법은 1. orElse() 이 메서드는 값을 인수로 받아들이고 Optional이 비어 있으면 이 값을 반환합니다. 이 인수의 유형은 Optional 유형과 동일해야 합니다.
// simple pizza
Pizza plainPizza = new Pizza();
plainPizza.setDescription("Pizza without any toppings");
// create empty Optional
Optional<Pizza> empty = Optional.empty();
// get pizza from optional
Pizza p = empty.orElse(plainPizza);
System.out.print(p.getDescription())
이 예제에서는 빈 Optional을 생성한 다음 기본 객체를 인수로 사용하여 orElse() 메서드를 호출합니다. 이 코드의 출력은 다음과 같습니다
Pizza without any toppings
이는 orElse()가 반환한 객체가 해당 인수와 동일함을 보여줍니다. 2. orElseGet() 이 메서드는 orElse()와 유사하며 Optional이 비어 있으면 값을 반환합니다. 이는 java.util.function.Supplier 유형의 인수를 허용하므로 공급자가 반환한 값을 반환합니다.
orElseGet()의 예가 앞서 제공됩니다.
// create empty optional
Optional<String> empty = Optional.empty();
String s = empty.orElseGet(() -> "Optional is empty");
System.out.println(s);
결과
Optional is empty
공급자가 기능적 인터페이스이기 때문에 orElseGet() 메서드에 대한 인수는 Lambda 표현식입니다. 위 구문이 혼란스러워 보인다면 orElseGet()에 대한 호출을 별도의 줄로 나누는 아래 코드를 살펴보세요.
// define a supplier
Supplier<String> supplier = () -> "Optional is empty";
String s = empty.orElseGet(supplier);
Difference between orElse() & orElseGet() 1. 두 메소드 사이의 눈에 띄는 차이점은 orElse()는 Optional 객체와 동일한 유형의 인수를 허용하는 반면 orElseGet() 메소드는 java.util.function.Supplier 유형의 인수를 허용한다는 것입니다.
2. 또 다른 차이점은 orElse()가 단순히 제공된 인수를 반환하는 반면 orElseGet()은 결과를 검색하기 위해 공급자 메서드를 호출한다는 것입니다.
3. 하지만 그 이면에는 또 다른 차이점이 있는데, 이 차이점은 아래 예에서 확인할 수 있습니다.
private void getData() {
System.out.println("Fetching data");
}
// create non-empty optional
Optional<String> o = Optional.of("Learning optional");
System.out.println("------------ orElse ------------");
// using orElse
String s = o.orElse(getData());
System.out.println(s);
System.out.println("\n------------orElseGet-------------");
// using orElseGet
s = o.orElseGet(() -> getData());
System.out.println(s);
orElse() 및 orElseGet()에 값을 직접 제공하는 대신 값을 반환하는 메서드를 호출합니다.
이 코드를 실행하면 다음과 같은 출력이 생성됩니다.
———— orElse ———— Fetching data Learning optional
————orElseGet————- Learning optional
이 출력에서 Optional이 비어 있지 않더라도 orElse()는 여전히 메서드를 실행하는 반면 orElseGet()은 Optional이 비어 있는 경우에만 메서드를 실행합니다.
이는 데이터를 가져오는 데 관련된 네트워크 또는 데이터베이스 호출이 있는 경우 상당히 중요합니다. 3. or() 이 메소드는 Java 9에 추가되었습니다. Optional에 값이 포함되어 있으면 동일한 Optional을 반환하고 그렇지 않으면 다른 기본 Optional 개체를 반환합니다.
or()는 java.util.function.Supplier 유형의 인수를 기대합니다. 반환된 기본 Optional은 이 인수 공급자 함수에 의해 제공됩니다.
String s = "optional value";
// create an optional
Optional<String> o = Optional.ofNullable(s);
// get Optional with or
Optional<String> or = o.or(()-> Optional.of("Default"));
System.out.println("Optional value:: " + or.get());
// create an optional with null value
Optional<String> empty = Optional.ofNullable(null);
// get Optional with or
Optional<String> defaultOptional = empty.or(()-> Optional.of("Default"));
System.out.println("Optional value:: " + defaultOptional.get());
결과
Optional value:: Optional value Optional value:: Default
Optional에 값이 포함되어 있으면 또는 동일한 Optional을 반환합니다. 그러나 비어 있으면 or의 인수 함수에서 제공하는 Optional이 반환됩니다.
Throwing exceptions 지금까지 Optional이 비어 있는 경우 기본값을 반환하는 방법을 살펴보았습니다. 그러나 때로는 비어 있는 Optional을 오류로 간주해야 하는 경우도 있습니다.
이러한 상황을 처리하기 위해 Optional이 비어 있을 때 오류가 발생할 수도 있습니다. 이에 대한 방법은 다음과 같습니다 1. orElseThrow(Supplier) 이 메소드는 공급자 인터페이스 유형의 인수를 승인하고 이 공급자 함수에 의해 반환되는 예외를 발생시킵니다.
orElseThrow()는 Optional이 비어 있는 경우에만 예외를 발생시킵니다.
// create empty optional
Optional<String> o = Optonal.ofNullable(null);
// throw exception when optional does not have any value
o.orElseThrow(() -> new IllegalArgumentException("Empty Optional"));
결과
Exception in thread “main” java.lang.IllegalArgumentException: Empty Optional at com.codippa.demo.DemoApplication.lambda$0(DemoApplication.java:22) at java.base/java.util.Optional.orElseThrow(Optional.java:408) at com.codippa.demo.DemoApplication.main(DemoApplication.java:22)
2. orElseThrow() 이 메소드는 위에서 설명한 orElseThrow()와 유사하지만 어떤 인수도 허용하지 않으며 Optional이 비어 있는 경우 기본적으로 "값이 없습니다"라는 오류 메시지와 함께 java.util.NoSuchElementException을 발생시킵니다.
// create empty optional
Optional<String> o = Optonal.ofNullable(null);
// throw exception when optional does not have any value
o.orElseThrow();
결과
Exception in thread “main” java.util.NoSuchElementException: No value present at java.base/java.util.Optional.orElseThrow(Optional.java:382) at com.codippa.demo.DemoApplication.main(DemoApplication.java:22)
이 메소드는 Java 10에 추가되었습니다. Filtering data 값이 특정 기준을 충족하는 경우에만 결과를 반환하려는 조건이 있을 수 있습니다.
Optional은 일치할 조건을 나타내는 Predicate를 허용하고 값이 조건자(또는 조건)와 일치하면 Optional 개체를 반환하고 그렇지 않으면 빈 Optional을 반환하는 필터 메서드를 제공합니다. Example,
Laptop apple = new Laptop("Apple");
Optional<Laptop> laptop = Optional.of(apple);
// check if
Optional<Laptop> o = laptop.filter((l) -> "Apple".equals(l.getBrand()));
System.out.println(o.orElseThrow());
위의 예에서는 노트북 브랜드를 확인하고 브랜드가 Apple이 아닌 경우 빈 Optional을 반환하도록 필터링합니다.
제공된 Predicate가 false를 반환하는 경우, 즉 조건이 일치하지 않는 경우 filter() 메서드는 빈 Optional을 반환합니다. orElseThrow는 반환된 Optional이 비어 있으면 예외를 발생시킵니다.
Transforming Optional map 및 flatMap 메소드를 사용하여 일부 유형의 Optional을 다른 유형의 Optional로 변환하는 것이 가능합니다.
map() map()은 인수를 승인하고 값을 반환하는 단일 메소드가 있는 기능적 인터페이스인 java.util.function.Function 유형의 인수를 승인합니다.
map() 인수 함수는 매퍼 함수라고도 합니다.
아래 map() 메소드 예는 Optional<Laptop>을 Optional<String>으로 변환합니다.
Laptop apple = new Laptop("Apple");
// create Optional object
Optional<Laptop> laptop = Optional.of(apple);
// map laptop Optional to a string Optional
Optional<String> strOptional = laptop.map(l -> l.getBrand());
// get Optional value
String brand = strOptional.get();
System.out.println(brand); //prints Apple
다음은 위 예의 지도 방법과 관련된 몇 가지 중요한 사항입니다.
map(l -> l.getBrand()) 문에서 map에는 단일 인수가 포함된 Lambda 표현식이 제공되며 이는 값을 반환합니다. map()은 map()에 인수로 제공된 Lambda 표현식의 반환 유형으로 수정된 유형의 Optional을 반환합니다. 따라서 위의 예에서 map()은 String 유형의 Optional을 반환합니다.
map()은 Optional을 반환하므로 map() 뒤에 다른 Optional 메서드를 연결하는 것이 가능합니다.
두 번째 map() 메소드에 대한 값 유형은 첫 번째 map() 메소드에서 반환된 Optional 유형인 String입니다. 인수 함수가 null을 반환하면 map()은 빈 Optional을 반환합니다. flatMap() Optional 객체를 변환하는 또 다른 방법은 flatMap() 메서드를 사용하는 것입니다.
map() 메소드와 flatMap() 메소드에는 두 가지 차이점이 있습니다. 1. flatMap()의 인수는 반환 유형이 Optional 객체인 함수를 기대하는 반면, map() 메소드의 인수는 위 예에서 반환 유형이 문자열과 같은 값인 함수를 기대합니다.
2. map()은 일부 유형의 값을 래핑하는 Optional을 반환하지만 flatMap()은 값을 직접 반환하며 Optional을 반환하지 않습니다.
3. flatMap()은 Optional 인수가 비어 있으면 Optional을 반환하고 Optional 인수가 비어 있지 않으면 값을 반환하며, map()은 두 경우 모두 Optional을 반환합니다. flatMap()의 예는 다음과 같습니다.
Optional<Laptop> laptop = Optional.of(apple);
String result = laptop.flatMap(l -> l.getBrandOptional()).orElseThrow();
System.out.println(result); // prints Apple
이 예에서 getBrandOptional() 메소드는 브랜드 값을 래핑하는 Optional<String>을 반환하므로 flatMap()은 브랜드 값을 직접 반환합니다.
How Optional avoids NullPointerException 이 기사의 시작 부분에서 NullPointerException을 나타내는 다음과 같은 문제가 논의되었습니다.
String country = student.getStudentDetails().getAddress().getCountry().toLowerCase();
이를 방지하려면 여러 개의 Null 검사가 필요했거나 솔루션이 Optional을 사용하고 있었습니다.
이제 Optional에 대해 배운 후에는 Optional이 NullPointerException을 어떻게 방지하는지 생각해야 합니다.
이 예제에 사용된 모든 클래스를 아래와 같이 수정합니다.
class Student{
StudentDetails studentDetails;
public Optional<StudentDetails> getStudentDetails() {
return Optional.ofNullable(studentDetails);
}
}
class StudentDetails {
Address address;
public Optional<Address> getAddress(){
return Optional.ofNullable(address);
}
}
class Address {
private Country country;
public Optional<Country> getCountry(){
return Optional.ofNullable(country);
}
}
class Country {
private String country;
public Optional<String> getCountry(){
return Optional.ofNullable(country);
}
}
보시다시피, getter 메소드는 이제 객체 대신 필요한 객체를 직접 래핑하는 Optional을 반환합니다. 국가를 얻으려면 명령문이 다음과 같이 작성됩니다.
Student st = null;
String country = Optional.ofNullable(st).
flatMap(s -> s.getStudentDetails()).
flatMap(sd -> sd.getAddress()).
flatMap(a -> a.getCountry()).
flatMap(c -> c.getCountry()).
orElse("Country not found");
flatMap()에 대한 각 호출은 Optional 객체를 반환하고 마지막으로 getCountry()에서 반환된 Optional이 비어 있으면 오류 메시지가 반환되지만 NullPointerException은 반환되지 않습니다.