검색결과 리스트
글
java 8 정리4
인프런 강의 6일차.
- 더 자바, Java 8 (백기선 강사님)
1. Optional
- 람다가 하는 일이 기존 메소드 또는 생성자를 호출하는 거라면, 메소드 레퍼런스를 사용해서 매우 간결하게 표현가능
- 오직 값 한 개가 들어있을 수도, 없을 수도 있는 컨테이너.
- 자바 프로그래밍에서 NullPointException을 종종 보는 이유
> null을 리턴하니까!
> && 체크를 깜빡했으니까!
- 메소드에서 작업 중 특별한 상황에서 값을 제대로 리턴할 수 없는 경우 선택할 수 있는 방법
> 예외를 던진다. (스택 트레이스를 찍게되므로 비싸다..)
> null을 리턴한다. (비용 문제가 없지만 그 코드를 사용하는 클라이언트가 주의해야한다)
> Optional을 리턴한다. (클라이언트 코드에게 명시적으로 빈 값일 수 있다는 걸 알려주고, 빈 값인 경우에 대한 처리를 강제한다.)
2. Optional 주의사항
- 리턴 값으로만 쓰기를 권장한다. (메소드 매개변수 타입, 맵의 키 타입, 인스턴스 필드 타입으로 쓰지 말자.)
> 맵의 key는 비어있을 수가 없다라는 것의 맵의 기본 요건!(key가 빈 값이라는 것은 설계의 문제..)
- Optional을 리턴하는 메소드에서 null을 리턴하지 말자
- 프리미티브 타입용 Optional은 따로 있다. OptionalInt, OptionalLong, ...
> Optional.of(10) 처럼 사용이 가능하긴하나, boxing, unboxing이 일어나는 과정에서 cost가 소모되기 때문에 OptionalInt 를 사용하는 것이 바람직하다.
- Collection, Map, Stream, Array, Optional은 Optional로 감싸지 말것!
package me.whiteship.java8to11;
import java.util.Optional;
public class OnlineClass {
private Integer id;
private String title;
private boolean closed;
private Progress progress;
public OnlineClass(Integer id, String title, boolean closed) {
this.id = id;
this.title = title;
this.closed = closed;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public boolean isClosed() {
return closed;
}
public void setClosed(boolean closed) {
this.closed = closed;
}
public Optional<Progress> getProgress() {
//Optional.of(param)의 경우 param이 null이 아니어야 한다. null일 경우 NullException이 발생한다.
//Optional.ofNullable(param)의 경우 param이 null이면 empty로 취급해준다.
//리턴타입이 Optional인데 return null같은 코드는 사용하지말자.. 정 리턴할게 없다면 Optional.empty를 사용1
return Optional.ofNullable(progress); //Optional 은 return type으로 쓰는 것이 권장사항.
}
/*
Optional을 파라미터에 선언하는 것은 문법적으로 문제가 없으나 쓸 수 없다!!
public void setProgress(Optional<Progress> progress) {
//만약 Optional<Progress> progess 처럼 메소드 매개변수 타입으로 사용하고자 한다면 해당 함수 내에서 체크를 해줘야한다.
progress.ifPresent(p -> this.progress = p); //해당 메소드를 호출할 때 파라미터가 null이 올 수 있기 때문에 위험하다.
//this.progress = progress;
}
*/
public void setProgress(Progress progress) {
this.progress = progress;
}
}
3. Optional 만들기
- Optional.of()
- Optional.ofNullable()
- Optional.empty()
4. Optional에 값이 있는지 없는지 확인
- ifPresent()
- isEmpty() (Java 11부터 제공)
5. Optional에 있는 값 가져오기
- get()
- 만약에 비어있는 Optional에서 무언가를 꺼낸다면?
6. Optional에 값이 있는 경우에 그 값을 가지고 ~~를 하라.
- ifPresent(Consumer)
7. Optional에 값이 있으면 가져오고 없는 경우에 ~~를 리턴하라.
- orElse(T)
> 이미 만들어져 있는 인스턴스를 참고할 때는 orElse가 적합
8. Optional에 값이 있으면 가져오고 없는 경우에 ~~를 하라.
- orElseGet(Supplier)
> 동적으로 추가 작업을 해야하는 상황이라면 orElse 대신 orElseGet이 적합하다.
9. Optional에 값이 있으면 가져오고 없는 경우 에러를 던져라
- orElseThrow()
> orElseThrow(IllegralStateException::new) 처럼 발생시킬 익셉션을 정의할 수 있다.
10. Optional에 들어있는 값 걸러내기
- Optional filter(Predicate)
> 값이 있다는 가정 하게 동작하는 것.
11. Optional에 들어있는 값 변환하기
- Optional map(Function)
- Optional flatMap(Function): Optional 안에 들어있는 인스턴스가 Optional인 경우에 사용하면 편리하다.
package me.whiteship.java8to11;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class App {
public static void main(String[] args) {
List<OnlineClass> springClasses = new ArrayList<>();
springClasses.add(new OnlineClass(1, "spring boot", true));
springClasses.add(new OnlineClass(2, "spring data jpa", true));
springClasses.add(new OnlineClass(3, "spring mvc", true));
springClasses.add(new OnlineClass(4, "spring core", true));
springClasses.add(new OnlineClass(5, "rest api development", false));
OnlineClass spring_boot = new OnlineClass(1, "spring boot", true);
/* java8 이전의 null처리 방식
Progress progress = spring_boot.getProgress(); //getProgress의 return은 null인 상태!
if(progress != null){
System.out.println(studyDuration);
}
*/
//spring으로 시작하는 oc 중 가장 첫번째 값 리턴 시 optional로 변수가 선언됨
Optional<OnlineClass> optionalOnlineClass = springClasses.stream()
.filter(oc -> oc.getTitle().startsWith("spring"))
.findFirst();
//spring에 값이 있는지 없는지 검사
boolean present = optionalOnlineClass.isPresent();
System.out.println(present);
//jpa로 시작하는 수업 중 첫번째 값 가져오기
Optional<OnlineClass> optionalOnlineClass1 = springClasses.stream()
.filter(oc -> oc.getTitle().startsWith("jpa"))
.findFirst();
boolean presentJpa = optionalOnlineClass1.isPresent();
System.out.println(presentJpa);
//값이 있으면 타이틀 출력
optionalOnlineClass.ifPresent(oc -> System.out.println(oc.getTitle()));
//jpa로 시작하는 수업이 있으면 가져오고, 없을 경우 createNewJpaClass를 새로 수행하여 클래스 생성
//다만 optional에 값이 있더라도 createNewJpaClass메소드는 항상 실행된다(return을 하지 않을 뿐!)
//이러한 현상을 방지하고자 orElseGet(Supplier)를 사용한다.orElse는 Supplier가 아닌 orElse(onlineClass)이다
OnlineClass onlineClass = optionalOnlineClass.orElse(createNewJpaClass());
System.out.println(onlineClass.getTitle());
OnlineClass onlineClass1 = optionalOnlineClass1.orElseGet(() -> createNewJpaClass());//람다표현식 사용
// optionalOnlineClass1.orElseGet(App::createNewJpaClass); //메소드 레퍼런스 사용
optionalOnlineClass1.orElseThrow(); //값이 없으면 NoSuchElementException인 RuntimeException을 던진다.
optionalOnlineClass1.orElseThrow(IllegalStateException::new); //발생시킬 exception을 정의할 수 있다.
//spring으로 시작하는 클래스 중 closed가 안된 대상을 필터 : true값이 없으므로 empty가 리턴된다.
Optional<OnlineClass> onlineClass2 = optionalOnlineClass.filter(oc -> !oc.isClosed());
System.out.println(onlineClass2.isEmpty()); //비어있는 optional이 나오게 된다.
//spring으로 시작하는 클래스의 id를 map으로 만듦
Optional<Integer> integer = optionalOnlineClass.map(OnlineClass::getId);
System.out.println(integer.isPresent()); //map 데이터가 있는지 확인
//만약 map의 리턴 타입이 Optional이면 좀 복잡해진다.
//map의 리턴타입은 Optional<Optional<Progress>> 임.
Optional<Optional<Progress>> progress = optionalOnlineClass.map(OnlineClass::getProgress); //progress의 리턴은 Optional
Optional<Progress> progress1 = progress.orElseThrow(); //progress에서 한번 더 꺼내야만 실제 확인이 가능한 변수가 됨
//위와 같은 형태를 줄이고자 할 때 사용하는 것이 flatMap
//map과 다르게 리턴 타입이 Optional<Progress> 임.
//orElseThrow를 하지는 않지만 구현이 비슷하게 된다고 알아두면 됨.(flatMap은 없을 때 optional.empty임)
Optional<Progress> progress2 = optionalOnlineClass.flatMap(OnlineClass::getProgress);
//Stream에서 쓰는 map은 Input:Output이 1:1 매핑, flatMap은 1:n 매핑이니 헷갈리지 말자!
//get 보다는 가급적 다른 메소드를 사용하자.
}
private static OnlineClass createNewJpaClass() {
System.out.println("creating new online class");
return new OnlineClass(10, "New Class", false);
}
}
'Java 정리' 카테고리의 다른 글
java 8 정리6 (0) | 2021.05.21 |
---|---|
java 8 정리5 (0) | 2021.05.20 |
java 8 정리3 (0) | 2021.05.17 |
java 8 정리2 (0) | 2021.05.13 |
java 8 정리1 (0) | 2021.05.12 |