이 글은 유튜브 '자바의 정석 - 기초편'을 보고 정리한 글입니다.
📂content
1. Optional<T>
⚝ T 타입 객체의 래퍼클래스 - Optional<T>
public final class Optional<T> {
private final T value; //T타입의 참조변수
...
}
1. 래퍼클래스?
- 기본 자료타입(primitive type)을 객체로 다루기 위해서 사용하는 클래스
- T타입의 참조변수를 갖고 있음.
- Integer, Long 등
2. Optional?
Optional도 래퍼클래스인데 제네릭이 T라서 어떤 타입이든지 다 저장이 가능하다.
=> 모든 종류의 객체 저장 가능 (Null도 가능)
3. Optional 필요한 이유
Optional을 이용하면 Null을 간접적으로 처리 가능
① null을 직접 다루는 것은 위험 => NullPointException발생 가능
② null을 직접 다루게 되면 null체크를 해야함 -> if문 필수 -> 코드 지저분함.
Object result = getResult(); //반환값은 null or 객체 result.toString();
만약 result가 Null이면 NullPointException이 발생한다. 그래서 처리하는 if문이 들어가야 한다.
즉, result에 Null을 직접 담았다면, Optional객체에 Null을 담는 것이다. 그리고 result에 Optional객체의 주소값을 준다. 그러므로 result값은 항상 Null이 아니게 되는 것이다. 이는 String과 비슷하다.
String str = Null; //사용 X String str = ""; //빈문자열 사용. new char[0]. 길이가 0인 char배열을 사용하는 것과 같다.
2. Optional<T> 객체 생성하기
⚝ Optional<T> 객체를 생성하는 다양한 방법
String str = "abc";
Optional<String> optVal = Optional.of(str);
Optional<String> optVal = Optional.of("abc");
Optional<String> optVal = Optional.of(null); // NullPointerException발생
Optional<String> optVal = Optional.ofNullable(null); // OK
String str = "abc";를 보면 str에 "abc"의 메모리주소를 저장하고 있다.
Optional<String> optVal = Optional.of(str);가 실행되면 optVal은 Optional객체의 메모리주소값이 들어있고,
Optional 객체의 value값에 String str값이 들어가는 것이다.
public final class Optional<T> { private final T value; ... }
직접 String을 다루는 대신에 Optional객체를 사용하면서 한 단계를 더 거치게 되는 것이다.
⚝ null 대신 빈 Optional<T>객체를 사용하자
Optional<String> optVal = null; //널로 초기화. 바람직하지 않음
Optional<String> optVal = Optional.<String>empty(); //빈 객체로 초기화. '=' 뒤의 <String> 생략 가능
인스턴스 변수 초기화할 때, null을 사용하여 초기화하지 말자.
Null 사용을 최소화하자!Object[] objArr = null; (X) Object[] objArr = new Object[0]; (O)
3. Optional<T> 객체의 값 가져오기
⚝ Optional객체의 값 가져오기 - get(), orElse(), orElseGet(), orElseThrow()
Optional<String> optVal = Optional.of("abc");
String str1 = optVal.get(); // optVal에 저장된 값을 반환. null이면 예외발생
String str2 = optVal.orElse(""); // optVal에 저장된 값이 null일 때는, ""를 반환
String str3 = optVal.orElseGet(String::new); // 람다식 사용가능 () -> new String()
String str4 = optVal.orElseThrow(NullPointerException::new); // 널이면 예외발생
null일 때 예외를 발생할 수 있는 str1과 같은 형식보다는 str2, str3을 많이 쓴다.
orElseGet은 람다식을 사용할 수 있다.
T orElseGet(Supplier<? extends T> other) T orElseThrow(Supplier<? extends X> exceptionSupplier)
str4가 str2,str3과 다른 것은 예외종류를 지정해줄 수 있다.
⚝ isPresent() - Optional객체의 값이 null이면 false, 아니면 true를 반환
if(Optional.ofNullable(str).isPresent()) { // if(str!=null) {
System.out.println(str);
}
// ifPresnt(Consumer) - 널이 아닐때만 작업 수행, 널이면 아무 일도 안 함
Optional.ofNullable(str).ifPresent(System.out::println);
4. OptionalInt, OptionalLong, OptionalDouble
⚝ 기본형 값을 감싸는 래퍼클래스
public final class OptionalInt {
...
private final boolean isPresent; // 값이 저장되어 있으면 true
private final int value; // int타입의 변수
Optional<T>가 있는데 왜 OptionalInt같은 것을 사용할까? 사실 Optional<T>를 사용해도 큰 상관은 없는데 말이다.
바로 성능때문이다. 람다와 스트림이 모든 것을 감싸고 있고, 모든 것을 객체로 다루고 있기 때문에 성능이 떨어진다. 그래서 더 높은 성능이 필요할 때 사용한다.
Optional<T>에서 value 타입은 T였는데, OptionalInt에서는 value의 타입이 int이다.
⚝ OptionalInt의 값 가져오기 - int getAsInt()
Optional 클래스 | 값을 반환하는 메서드 |
Optional<T> | T get() |
OptionalInt | int getAsInt() |
OptionalLong | long getAsLong() |
OptionalDouble | double getAsDouble() |
⚝ 빈 Optional 객체와의 비교
OptionalInt opt = OptionalInt.of(0); //OptionalInt에 0을 저장
OptionalInt opt2 = OptionalInt.empty(); //OptionalInt에 0을 저장
System.out.println(opt.isPresent()); // true
System.out.println(opt2.isPresent()); // false
System.out.println(opt.equals(opt2)); // false
.of(0)을 사용하면 OptionalInt의 value값에 0이 저장된다.
.empty()을 사용하면 OptionalInt의 value값에 아무 값도 저장을 안 하는 메소드이다.
하지만 int라서 초기값이 애초에 0이다.
그렇다면 이 둘을 어떻게 구분할 것인가? 그래서 OptionalInt에는 isPresent라는 boolean변수가 존재한다.
⍟실습
더보기
Ex14_8
import java.util.*;
class Ex14_8 {
public static void main(String[] args) {
Optional<String> optStr = Optional.of("abcde");
Optional<Integer> optInt = optStr.map(String::length); //메서드 참조
//Optional<Integer> optInt = optStr.map(s -> s.length()); //람다
System.out.println("optStr="+optStr.get());
System.out.println("optInt="+optInt.get());
int result1 = Optional.of("123")
.filter(x->x.length() >0)
.map(Integer::parseInt).get();
int result2 = Optional.of("")
.filter(x->x.length() >0)
.map(Integer::parseInt).orElse(-1);
System.out.println("result1="+result1);
System.out.println("result2="+result2);
Optional.of("456").map(Integer::parseInt)
.ifPresent(x->System.out.printf("result3=%d%n",x));
OptionalInt optInt1 = OptionalInt.of(0); // 0을 저장
OptionalInt optInt2 = OptionalInt.empty(); // 빈 객체를 생성
System.out.println(optInt1.isPresent()); // true
System.out.println(optInt2.isPresent()); // false
System.out.println(optInt1.getAsInt()); // 0
// System.out.println(optInt2.getAsInt()); // NoSuchElementException. 빈 객체라 예외발생
System.out.println("optInt1="+optInt1);
System.out.println("optInt2="+optInt2);
System.out.println("optInt1.equals(optInt2)?"+optInt1.equals(optInt2));
}
}
출처
'🎥Back > 자바의 정석' 카테고리의 다른 글
[JAVA의 정석]스트림의 연산 (0) | 2024.03.08 |
---|---|
[JAVA의 정석] 스트림 (0) | 2024.03.08 |
[JAVA의 정석]람다식과 함수형 인터페이스 (2) | 2024.03.06 |
[JAVA의 정석] 스레드와 관련된 함수 및 동기화 (0) | 2024.03.01 |
[JAVA의 정석]데몬 스레드, 스레드의 상태 (0) | 2024.02.29 |