클래스가 메모리에 올라갈 때 생성된다.
따라서 인스턴스를 생성하지 않아도 변수를 변경 및 조회가 가능하다.
따라서 모든 인스턴스들은 이 클래스 변수를 공유한다.
클래스이름.클래스변수
변수에 사용되면 값을 변경할 수 없는 상수에 선언
선언과 동시에 초기화되지만
생성자의 매개변수를 통해서 초기화 가능
같은 클래스 내에서만 접근
외부에서 접근하고자 할 때는 메서드를 통해서만 가능
직접 변경할 수 없음
같은 패키지 내에서만
같은 패키지 내, 그리고 다른 패키지의 자손 클래스에서 접근 가능
전체
//static이 붙고 클래스 영역에 선언된 변수를 클래스 변수라 하고 이는 클래스가 메모리에 올라갈 때 생성된다.
// 모든 인스턴스들은 이 클래스 변수를 공유한다.
// 그렇기 때문에 sequence는 static이다!
//한가지 더 추가하자면 static 변수를 클래스가 메모리에 올라갈 때 생성되므로
// 인스턴스를 생성하지 않고 사용할 수 있음 클래스이름.클래스변수
//private: 외부에서 변수를 직접 변경할 수 없고 메소들 통해서만 가능
//ID의 값을 순차적으로 늘려가기 위해서 private, static으로 선언
private static long sequence= 0L; //static 사용
// 따라서 아래와 같이 메서드를 통해서 sequence의 값을 변경할 수 있음
public Member save(Member member) {
member.setId(++sequence);
log.info("save: member={}", member);
store.put(member.getId(), member);
return member;
}
Wrapper class(래퍼 클래스)는 우리가 알고 있던 Long, Integer, Character 등이 래퍼클래스이다.
래퍼 클래스를 null 값이 올 수 있다 왜냐하면 객체로 선언되기 때문인데
즉 래퍼 클래스는 기본 타입을 객체 형태로 포장한다.
@Data
public class Item {
private Long id;
private String itemName;
private Integer price;
private Integer quantity;
null값이 올 수도 있기 때문에 래퍼 클래스로 선언된 것을 확인할 수 있다.
Optional<T>
Optional<T>
은 java8에서 제공하는 Wrapper class이다.
래퍼 클레스가 왜 쓰일까?
자바 프로그램에서 발생하는 NullPointerException을 더 간편하게 예방하기 위해서다. (이게 래퍼 클래스의 목적이다) 중요한 키워드는 더 간편하게!!
만약에 Optional<T>
없이 사용하면 if문을 통해서 도메인의 각 속성이 null이 아니라면 이라는 조건문을 걸어줘야 한다.
Item item = getItem();
if(item.price !=null && item.quantitu!=null && item.name !=null&&...){
...
}
Optional<T>
의 사용public final class Optional<T> {
...
/**
* If non-null, the value; if null, indicates no value is present
*/
private final T value;
...
}
앞서 배운 Long, String, Integer보다 더 포괄적인 래퍼 클래스로 지네릭으로 객체 타입을 명시할 수 있다.
따라서 Optional<String>, Optional<Item>
등이 가능하다.
Item item = getItem();
Optional.of(item)
.map(Item::getPrice)
.map(Item::getQuantity)
.map(Item::getName)
.ifPresent(n->System.out.println("ok"));
stream과 그 사용법이 유사하다.
Optional<T>
의 생성Optional<String> optional = Optional.of(value);
Optional<String> optional = Optional.ofNullable(value);
Optional<String> optional = Optional.empty();
Optional<T>
의 중간처리Optional 객체 -> 메서드 -> Optional 객체
따라서 중간처리 메서드는 이어서 붙이는 것이 가능=> 메서드 체인
Optional 객체 -> 메서드(람디식 true)-> Optional 객체
Optional.of("XYZ").filter(v -> v.startsWith("AB")).orElse("Not AB");
인자로 받은 람다식이 참이면 Optional 객체 그대로 통과
거짓이면 Optional.empty() 반환
Optional 객체 -> 메서드(변경을 가하는) -> 수정된 Optional 객체
Optional.of("XYZ").map(String::toLowerCase).orElse("Not AB");
Optional<T>
의 값 리턴메소드 체인 불가능
Optional 객체가 아닌 값을 리턴한다.
Optional 객체의 값이 null인지 아닌지
Optional.of("ABC").isPresent(); // true
람다식을 인자로 받아 값이 존재하면 람다식 실행
Optional.of("ABC").ifPresent(System.out::println);
Optional 객체가 가지고 있는 value값 꺼내온다.
orElse("기본값")
중간처리 메소드의 결과값이 null 경우 기본값 리턴
Optional<T>
활용✨//MemberRepository에서의 함수의 return 값이 Optional 객체
public Optional<Member> findByLoginId(String loginId) {
return findAll().stream()
.filter(m->m.getLoginId().equals(loginId))
.findFirst();
}
조회시 없을 수도 있기 때문에 리턴값을 Optional 객체로 설정한 것을 확인할 수 있다. 즉 어떤 조회 기능에서 null값이 나와도 NullPointException이 되지 않도록 하기 위한 방법이다.
로그인 처리 서비스에서 위 함수를 이용할 때
public Member login(String loginId, String password){
return memberRepository.findByLoginId(loginId)
.filter(m->m.getPassword().equals(password))
.orElse(null);
//stream과 언뜻 비슷해 보이는 Optional
//반드시 값이 있어야 하는 경우
//변수의 값이 null 일 수 있음 -> null인 경우 Optional.empty() 리턴
//Optional 중간처리 메서드 처리하고 다시 Optional객체 반환
//filter 람다신 참이면 통과 아니면 Optional.empty() 반환
//null일 때 orElse() 메서드가 기본값 null 반환
}