[Java]Optional

gengarยท2022๋…„ 4์›” 6์ผ
0

Java

๋ชฉ๋ก ๋ณด๊ธฐ
1/3
post-thumbnail

1. Optional?

NPE(NullPointerException)

๊ฐœ๋ฐœ์„ ํ•  ๋•Œ ๊ฐ€์žฅ ๋งŽ์ด ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ฐ”๋กœ NPE์ด๋‹ค.
NPE๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” null ๊ฒ€์‚ฌ ๋กœ์ง์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š”๋ฐ, null ๊ฒ€์‚ฌ๋ฅผ ํ•ด์•ผํ•˜๋Š” ๋ณ€์ˆ˜๊ฐ€ ๋งŽ์€ ๊ฒฝ์šฐ ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์ง€๊ณ  ๋กœ์ง์ด ์ƒ๋‹นํžˆ ๋ฒˆ๊ฑฐ๋กญ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— null ๋Œ€์‹  ์ดˆ๊ธฐ ๊ฐ’์„ ์‚ฌ์šฉํ•˜๊ธธ ๊ถŒ์žฅํ•˜๊ธฐ๋„ ํ•œ๋‹ค.

List<String> names = getNames();
names.sort(); // names๊ฐ€ null์ด๋ผ๋ฉด NPE๊ฐ€ ๋ฐœ์ƒ

List<String> names = getNames();
// NPE๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด null ๊ฒ€์‚ฌ๋ฅผ ํ•ด์•ผํ•œ๋‹ค.
If(names != null) {
	names.sort();
}

Optional

Java8์—์„œ๋Š” Optional<T> ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•ด NPE๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค€๋‹ค. Optional<T>๋Š” null์ด ์˜ฌ ์ˆ˜ ์žˆ๋Š” ๊ฐ’์„ ๊ฐ์‹ธ๋Š” Wrapper ํด๋ž˜์Šค๋กœ, ์ฐธ์กฐํ•˜๋”๋ผ๋„ NPE๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ๋„์™€์ค€๋‹ค.
Optional ํด๋ž˜์Šค๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ value์— ๊ฐ’์„ ์ €์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ’์ด null์ด๋”๋ผ๋„ ๋ฐ”๋กœ NPE๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋ฉฐ, ํด๋ž˜์Šค์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์ข… ๋ฉ”์†Œ๋“œ๋ฅผ ์ œ๊ณตํ•ด์ค€๋‹ค.

public final class Optional<T> {
	
    // If non-null, the value; if null, indicates no value is present
    private final T value;
    
    ...
}
  • Wrapper class
    8๊ฐœ์˜ ๊ธฐ๋ณธ ํƒ€์ž…์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ์ฒด๋กœ ํฌ์žฅํ•ด์ฃผ๋Š” ํด๋ž˜์Šค

    ๊ธฐ๋ณธ ํƒ€์ž…๋ž˜ํผ ํด๋ž˜์Šค
    byteByte
    shortShort
    intInteger
    longLong
    floatFloat
    doubleDouble
    charCaracter
    booleanBoolean

2. Optional ํ™œ์šฉ

Optional ์ƒ์„ฑ

  • Optional.empty() - ๊ฐ’์ด ๋น„์–ด์žˆ๋Š” ๊ฒฝ์šฐ
    Optional์€ Wrapper ํด๋ž˜์Šค์ด๊ธฐ ๋•Œ๋ฌธ์— ๋นˆ ๊ฐ’์ด ์˜ฌ์ˆ˜๋„ ์žˆ๋Š”๋ฐ, ๋นˆ ๊ฐ์ฒด๋Š” Optional.empty()๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
Optional<String> optional = Optional.empty();

System.out.println(optional); // Optional.empty
System.out.println(optional.isPresent()); // false

Optional ํด๋ž˜์Šค๋Š” ๋‚ด๋ถ€์—์„œ static ๋ณ€์ˆ˜๋กœ EMPTY ๊ฐ์ฒด๋ฅผ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•ด์„œ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ด์œ ๋กœ ๋นˆ ๊ฐ์ฒด๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์ƒ์„ฑํ•ด์ค˜์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ 1๊ฐœ์˜ EMPTY ๊ฐ์ฒด๋ฅผ ๊ณต์œ ํ•จ์œผ๋กœ์จ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ ˆ์•ฝํ•˜๊ณ  ์žˆ๋‹ค.

public final class Optional<T> {
	
    private static final Optional<?> EMPTY = new Optional<>();
    private final T value;
    
    private Optional() {
    	this.value = null;
    }
    
    ...
}
  • Optional.of() - ๊ฐ’์ด Null์ด ์•„๋‹Œ ๊ฒฝ์šฐ
    ๋งŒ์•ฝ ์–ด๋–ค ๋ฐ์ดํ„ฐ๊ฐ€ null์ด ์ ˆ๋Œ€ ์•„๋‹Œ ๊ฒฝ์šฐ์—๋Š” Optional.of()๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
// Optional์˜ value๋Š” null์ด ์•„๋‹ˆ๋‹ค.
Optional<String> optional = Optional.of("MyName");

๋งŒ์•ฝ Optional.of() ๋กœ Null์„ ์ €์žฅํ•˜๋ ค๊ณ  ํ•˜๋ฉด NPE(NullPointerException) ์ด ๋ฐœ์ƒํ•œ๋‹ค.

  • Optional.ofNullbale() - ๊ฐ’์ด Null ์ผ์ˆ˜๋ก, ์•„๋‹์ˆ˜๋„ ์žˆ๋Š” ๊ฒฝ์šฐ
    ๋งŒ์•ฝ ์–ด๋–ค ๋ฐ์ดํ„ฐ๊ฐ€ null์ด ์˜ฌ ์ˆ˜๋„ ์žˆ๊ณ  ์•„๋‹ ์ˆ˜๋„ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” Optional.ofNullbale() ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ํ›„์— orElse ๋˜๋Š” orElseGet ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ๊ฐ’์ด ์—†๋Š” ๊ฒฝ์šฐ๋ผ๋„ ์•ˆ์ „ํ•˜๊ฒŒ ๊ฐ’์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.
// Optional์˜ value๋Š” ๊ฐ’์ด ์žˆ์„ ์ˆ˜๋„ ์žˆ๊ณ  null์ผ ์ˆ˜๋„ ์žˆ๋‹ค.
Optional<String> optional = Optional.ofNullable(getName());
String name = optional.orElse("anonymous");
// ๊ฐ’์ด ์—†๋‹ค๋ฉด "anonymous"๋ฅผ ๋ฆฌํ„ด

Optional ์‚ฌ์šฉ ์˜ˆ์‹œ ์ฝ”๋“œ

Optional ์‚ฌ์šฉ ์˜ˆ์‹œ (1)

๊ธฐ์กด์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด null ๊ฒ€์‚ฌ๋ฅผ ํ•œ ํ›„์— null์ผ ๊ฒฝ์šฐ์—๋Š” ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์–ด์•ผ ํ–ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ณผ์ •์„ ์ฝ”๋“œ๋กœ ๋‚˜ํƒ€๋‚ด๋ฉด ๋‹ค์†Œ ๋ฒˆ์žกํ•ด ๋ณด์ด๋Š”๋ฐ, Optional<T>์™€ Lambda๋ฅผ ์ด์šฉํ•˜๋ฉด ํ•ด๋‹น ๊ณผ์ •์„ ๋ณด๋‹ค ๊ฐ„๋‹จํ•˜๊ฒŒ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

// Java8 ์ด์ „
List<String> names = getNames();
List<String> tempNames = list != null
	? list
    : new ArrayList<>();
        
List<String> nameList = Optional.ofNullable(getList())
	.orElseGet(() -> new ArrayList<>());

Optional ์‚ฌ์šฉ ์˜ˆ์‹œ (2)

์˜ˆ๋ฅผ ๋“ค์–ด ์•„๋ž˜์™€ ๊ฐ™์€ ์šฐํŽธ๋ฒˆํ˜ธ๋ฅผ ๊บผ๋‚ด๋Š” null ๊ฒ€์‚ฌ ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค๊ณ  ์น˜์ž.

public String findPostCode() {
	UserVO userVO = getUser();
    if (userVO != null) {
    	Address address = user.getAddress();
        if (address != null) {
        	String postCode = address.getPostCode();
            if (postCode != null) {
            	return postCode;
            }
        }
    }
    return "์šฐํŽธ๋ฒˆํ˜ธ ์—†์Œ";
}

ํ•˜์ง€๋งŒ ์ด๋Ÿฌํ•œ ์ฝ”๋“œ๋ฅผ Optional์„ ์‚ฌ์šฉํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

public String findPostCode() {
	// ์œ„์˜ ์ฝ”๋“œ๋ฅผ Optional๋กœ ํŽผ์ณ๋†“์œผ๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.
    Optional<UserVO> userVO = Optional.ofNullable(getUser());
    Optional<Address> address = userVO.map(UserVO::getAddress);
    Optional<String> postCode = address.map(Address::getPostCode);
    String result = postCode.orElse("์šฐํŽธ๋ฒˆํ˜ธ ์—†์Œ");
    
    // ๊ทธ๋ฆฌ๊ณ  ์œ„์˜ ์ฝ”๋“œ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ถ•์•ฝํ•ด์„œ ์“ธ ์ˆ˜ ์žˆ๋‹ค.
    String result = user.map(UserVO::getAddress)
    .map(Address::getPostCode)
    .orElse("์šฐํŽธ๋ฒˆํ˜ธ ์—†์Œ");
}

Optional ์‚ฌ์šฉ ์˜ˆ์‹œ (3)

์˜ˆ๋ฅผ ๋“ค์–ด ์•„๋ž˜์™€ ๊ฐ™์ด ์ด๋ฆ„์„ ๋Œ€๋ฌธ์ž๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ์ฝ”๋“œ์—์„œ NPE ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ค€๋‹ค๊ณ  ํ•˜์ž.

String name = getName();
String result = "";

try {
	result = name.toUpperCase();
} catch (NullPointerException e) {
	throw new CustomUpperCaseException();
}

์œ„์˜ ์ฝ”๋“œ๋Š” ๋‹ค์†Œ ๋ฒˆ์žกํ•˜๊ณ  ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง€๋Š”๋ฐ ์ด๋ฅผ Optional๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

Optional<String> nameOpt = Optional.ofNullable(getName());
String result = nameOpt.orElseThrow(CustomUpperCaseException::new)
	.toUpperCase();

Optional ์ •๋ฆฌ
Optional์€ null ๋˜๋Š” ์‹ค์ œ ๊ฐ’์„ value ๋กœ ๊ฐ–๋Š” wrapper๋กœ ๊ฐ์‹ธ์„œ NPE(NullPointerException)๋กœ๋ถ€ํ„ฐ ์ž์œ ๋กœ์›Œ์ง€๊ธฐ ์œ„ํ•ด ๋‚˜์˜จ Wrapper ํด๋ž˜์Šค์ด๋‹ค. ๋˜ํ•œ Optional์€ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜์–ด๊ฐ€๋Š” ๋“ฑ์ด ์•„๋‹ˆ๋ผ ๋ฐ˜ํ™˜ ํƒ€์ž…์œผ๋กœ์จ ์ œํ•œ์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋„๋ก ์„ค๊ณ„ ๋˜์—ˆ๋‹ค.
Optional์€ ๊ฐ’์„ Wrapping ํ•˜๊ณ  ๋‹ค์‹œ ํ’€๊ณ , null์ผ ๊ฒฝ์šฐ๋Š” ๋Œ€์ฒดํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋“ฑ์˜ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์ž˜๋ชป ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ์„ ์ €ํ•˜์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.
๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”์†Œ๋“œ์˜ ๋ฐ˜ํ™˜ ๊ฐ’์ด ์ ˆ๋Œ€ null์ด ์•„๋‹ˆ๋ผ๋ฉด Optional์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์ฆ‰, Optional์€ ๋ฉ”์†Œ๋“œ์˜ ๊ฒฐ๊ณผ๊ฐ€ null์ด ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, null์— ์˜ํ•ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋งค์šฐ ๋†’์„ ๋•Œ ๋ฐ˜ํ™˜ ๊ฐ’์œผ๋กœ๋งŒ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•œ๋‹ค.

Reference๐Ÿ™‡๐Ÿป

๋ง๋‚˜๋‹ˆ๊ฐœ๋ฐœ์ž

profile
ํ•˜๋‚˜์— ๋ฌธ์ œ๋ฅผ! ๋‘˜์— ํ•ด๊ฒฐํ•˜์ž!๐Ÿค“

0๊ฐœ์˜ ๋Œ“๊ธ€