Skip to content

Latest commit

Β 

History

History
342 lines (237 loc) Β· 17.7 KB

File metadata and controls

342 lines (237 loc) Β· 17.7 KB

item 49 : λ§€κ°œλ³€μˆ˜κ°€ μœ νš¨ν•œμ§€ κ²€μ‚¬ν•˜λΌ

1. 였λ₯˜ κ²€μ‚¬μ˜ 일반 원칙1: 였λ₯˜λ₯Ό μ¦‰μ‹œ μž‘μ•„λΌ

였λ₯˜λŠ” κ°€λŠ₯ν•œ ν•œ 빨리 λ°œμƒν•œ κ³³μ—μ„œ μž‘μ•„μ•Ό ν•œλ‹€.

였λ₯˜λ₯Ό λ°œμƒν•œ μ¦‰μ‹œ μž‘μ§€ λͺ»ν•˜λ©΄ ν•΄λ‹Ή 였λ₯˜λ₯Ό κ°μ§€ν•˜κΈ°λ„ μ–΄λ ΅κ³ , μ •ν™•νžˆ μ–΄λ””μ„œ λ°œμƒν–ˆλŠ”μ§€ μ•ŒκΈ°λ„ μ–΄λ ΅λ‹€.

1) λ‹€μ–‘ν•œ λ§€κ°œλ³€μˆ˜ 검사 μ˜ˆμ‹œ (κ°€μž₯ κ°„λ‹¨ν•œ 원칙)

  1. 인덱슀 값은 음수이면 μ•ˆ λœλ‹€.
  2. 객체 μ°Έμ‘°λŠ” null 이 μ•„λ‹ˆμ–΄μ•Ό ν•œλ‹€.

2) λ§€κ°œλ³€μˆ˜ 검사λ₯Ό μ œλŒ€λ‘œ ν•˜μ§€ λͺ»ν–ˆμ„ λ•Œ λ²Œμ–΄μ§€λŠ” 일

μ•„λž˜μ™€ 같이 μ‹€νŒ¨ μ›μžμ„±(μ•„μ΄ν…œ 74)을 μ–΄κΈ°λŠ” λ¬Έμ œκ°€ λ°œμƒν•œλ‹€.

  1. λ©”μ„œλ“œκ°€ μˆ˜ν–‰λ˜λ‹€κ°€ λͺ¨ν˜Έν•œ μ˜ˆμ™Έλ₯Ό λ˜μ§€λ©° μ‹€νŒ¨ν•œλ‹€.
  2. λ©”μ„œλ“œκ°€ 잘 μˆ˜ν–‰λ˜μ§€λ§Œ 잘λͺ»λœ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•œλ‹€.
  3. λ©”μ„œλ“œμ—μ„œ μ‚¬μš©ν•œ λ‹€λ₯Έ 객체λ₯Ό μ΄μƒν•œ μƒνƒœλ‘œ λ§Œλ“€μ–΄ 미래의 μ•Œ 수 μ—†λŠ” μ‹œμ μ— λ¬Έμ œκ°€ λ°œμƒν•œλ‹€.

μ•„λž˜ λ‹¨κ³„μ˜ ν˜„μƒμΌμˆ˜λ‘ λ¬Έμ œλŠ” λ”μš± 심각해진닀.

μ˜ˆμ™Έμ˜ λ¬Έμ„œν™”

μžλ°”λ…μ˜ @throws νƒœκ·Έλ₯Ό μ΄μš©ν•΄μ„œ κ°€λŠ₯ν•˜λ‹€.

IllegalArgumentException, IndexOutOFBoundsException, NullPointerException 쀑 ν•˜λ‚˜κ°€ 될 것이닀.

{% hint style="danger" %} λ©”μ„œλ“œμ™€ μƒμ„±μžλŠ” μž…λ ₯ λ§€κ°œλ³€μˆ˜μ˜ 값이 νŠΉμ • 쑰건을 λ§Œμ‘±ν•΄μ•Ό ν•˜λŠ” κ²½μš°κ°€ λ§Žμ€λ°, μ΄λŸ¬ν•œ 경우 였λ₯˜λŠ” κ°€λŠ₯ν•œ ν•œ 빨리 검사해야 ν•˜λŠ” 것이 μ’‹μœΌλ―€λ‘œ λ©”μ„œλ“œ λͺΈμ²΄κ°€ μ‹œμž‘λ˜κΈ° 전에 λ§€κ°œλ³€μˆ˜λ₯Ό κ²€μ‚¬ν•˜λŠ” 것이 μ’‹λ‹€. {% endhint %}

2. λ§€κ°œλ³€μˆ˜λ₯Ό κ²€μ‚¬ν•˜λŠ” 방법 : 곡개 λ©”μ„œλ“œ

1) @throws

publicκ³Ό protected λ©”μ„œλ“œλŠ” λ§€κ°œλ³€μˆ˜ 값이 잘λͺ»λμ„ λ•Œ λ˜μ§€λŠ” μ˜ˆμ™Έλ₯Ό @throws μžλ°”λ… νƒœκ·Έλ₯Ό ν™œμš©ν•΄ λ¬Έμ„œν™”ν•΄μ•Ό ν•œλ‹€.

λ°œμƒν•˜λŠ” μ˜ˆμ™ΈλŠ” 보톡 IllegalArgumentException, IndexOutOfBoundsException, NullPointerException 쀑 ν•˜λ‚˜κ°€ 될 것이닀(μ•„μ΄ν…œ 72)

/**
(ν˜„μž¬ κ°’ mod m)을 λ°˜ν™˜ν•œλ‹€. 
...
@param m κ³„μˆ˜(μ–‘μˆ˜μ—¬μ•Ό ν•œλ‹€.)
@return ν˜„μž¬ κ°’ Mod m
@thorws ArithmeticException m이 0보닀 μž‘κ±°λ‚˜ κ°™μœΌλ©΄ λ°œμƒν•œλ‹€.
*/
public BigInteger mod(BigInteger m){
	if (m.signum() <= 0){
    	throw new ArithmeticException("κ³„μˆ˜(m)λŠ” μ–‘μˆ˜μ—¬μ•Ό ν•©λ‹ˆλ‹€. " + m);
    ...
}
  • 이 λ©”μ„œλ“œμ˜ @throws νƒœκ·ΈλŠ” 0보닀 μž‘κ±°λ‚˜ 같은 κ°’μ˜ λ‚˜λ¨Έμ§€λ₯Ό κ΅¬ν•˜λ € ν•˜λ©΄, ArithmeticException이 λ°œμƒν•œλ‹€κ³  μΉœμ ˆν•˜κ²Œ μ•Œλ €μ£Όκ³  μžˆλ‹€.
All methods and constructors in this class throw {@code NullPointerException}
when passed a null object reference for any input parameter

클래슀 전체 μ„€λͺ…μ—λŠ” μœ„μ™€ 같이 λͺ¨λ“  λ©”μ„œλ“œμ™€ μƒμ„±μžκ°€ NullPointerException을 던질 수 μžˆλ‹€λŠ” 점을 λ‚΄ν¬ν•˜κ³  μžˆλ‹€λŠ” 점도 λ³Όλ§Œν•˜λ‹€. κ·Έλž˜μ„œ λ‹€λ₯Έ λ©”μ„œλ“œλ“€μ— λ”°λ‘œ @throws NullPointerException을 적어주진 μ•Šκ³  μžˆλ‹€.

2) null κ²€μ‚¬μ‹œ requireNonNull

@Nullable μ΄λ‚˜ λΉ„μŠ·ν•œ μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜μ—¬ νŠΉμ • λ§€κ°œλ³€μˆ˜λŠ” null이 될 수 μžˆλ‹€κ³  μ•Œλ €μ€„ 수 μžˆμ§€λ§Œ, ν‘œμ€€μ μΈ 방법은 μ•„λ‹ˆλ‹€.

λŒ€μ‹  μžλ°” 7μ—μ„œ μΆ”κ°€λœ java.util.Objects. requireNonNull λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•œλ‹€λ©΄ 더 이상 null 검사λ₯Ό μˆ˜λ™μœΌλ‘œ ν•˜μ§€ μ•Šμ•„λ„ λœλ‹€.

μ›ν•˜λŠ” μ˜ˆμ™Έ λ©”μ‹œμ§€λ„ 지정할 수 μžˆλ‹€. λ˜ν•œ μž…λ ₯을 κ·ΈλŒ€λ‘œ λ°˜ν™˜ν•˜λ―€λ‘œ 값을 μ‚¬μš©ν•˜λŠ” λ™μ‹œ 에 null 검사λ₯Ό μˆ˜ν–‰ν•  수 μžˆλ‹€

▢️ μƒμ„±μžμ—μ„œ Null 검사 κΈ°λŠ₯ ν™œμš©

this.strategy = Objects.requireNonNull(strategy, "μ „λž΅");  // μ˜ˆμ™Έ λ©”μ‹œμ§€ 지정
  • λ°˜ν™˜κ°’μ€ κ·Έλƒ₯ λ¬΄μ‹œν•˜κ³  ν•„μš”ν•œ κ³³ μ–΄λ””μ„œλ“  μˆœμˆ˜ν•œ null 검사 λͺ©μ μœΌλ‘œ μ‚¬μš© 해도 λœλ‹€.

3) Objects λ²”μœ„ 검사

μžλ°” 9λΆ€ν„°λŠ” checkFromIndexSize(), checkFromToIndex(), checkIndex() 와 같은 λ©”μ„œλ“œλ“€μ΄ μΆ”κ°€λ˜λ©΄μ„œ Objects에 λ²”μœ„ 검사 κΈ°λŠ₯도 λ”ν•΄μ‘Œλ‹€.

단 μ˜ˆμ™Έ λ©”μ‹œμ§€λ₯Ό 지정할 수 μ—†μœΌλ©° λ¦¬μŠ€νŠΈμ™€ λ°°μ—΄ μ „μš©μœΌλ‘œ μ„€κ³„λ˜μ—ˆλ‹€. λ˜ν•œ λ‹«νžŒ λ²”μœ„(μ–‘ λλ‹¨μ˜ 값을 ν¬ν•¨ν•˜λŠ”)λŠ” 닀루지 λͺ»ν•œλ‹€λŠ” 단점이 μ‘΄μž¬ν•œλ‹€.

κ·Έλž˜λ„ 이런 μ œμ•½μ΄ 걸림돌이 λ˜μ§€ μ•ŠλŠ” μƒν™©μ—μ„œλŠ” μ•„μ£Ό μœ μš©ν•˜κ³  νŽΈν•˜λ‹€.

Java 7μ—μ„œ μΆ”κ°€λœ null 검사 κΈ°λŠ₯: Objects.requireNonNull()

Objects.requireNonNull()은 Java 7μ—μ„œ μΆ”κ°€λœ λ©”μ„œλ“œλ‘œ, 전달받은 λ§€κ°œλ³€μˆ˜κ°€ null인지 κ²€μ‚¬ν•˜κ³  *null이라면 NullPointerException을 λ˜μ§„λ‹€.

주둜 λ©”μ„œλ“œ 인수의 μœ νš¨μ„± 검사에 μ‚¬μš©λ˜λ©°, null둜 인해 λ°œμƒν•  수 μžˆλŠ” 였λ₯˜λ₯Ό 미리 λ°©μ§€ν•œλ‹€.

μ•„λž˜λŠ” Objects.requireNonNull()의 μ‚¬μš© 예제

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.Objects;

public class Item49Test {

    @Test
    public void requireNonNullTest() {
        // null 값을 μ „λ‹¬ν•˜μ—¬ NullPointerException이 λ°œμƒν•˜λŠ”μ§€ 확인
        Assertions.assertThrows(NullPointerException.class, () -> {
            nullTest(null);
        });
    }

    public void nullTest(Object obj) {
        // 전달받은 객체가 null인지 ν™•μΈν•˜κ³ , null일 경우 μ˜ˆμ™Έ λ˜μ§€κΈ°
        Objects.requireNonNull(obj, "널이 λ“€μ–΄μ™”μŒ");
    }
}
  • Objects.requireNonNull()의 두 번째 인수둜 μ „λ‹¬λœ λ¬Έμžμ—΄μ€ μ˜ˆμ™Έ λ©”μ‹œμ§€λ‘œ μ‚¬μš©λœλ‹€. μ—¬κΈ°μ„œλŠ” "널이 λ“€μ–΄μ™”μŒ" λ©”μ‹œμ§€κ°€ ν¬ν•¨λ˜μ–΄ μ˜ˆμ™Έ λ°œμƒ μ‹œ 문제λ₯Ό 더 λͺ…ν™•ν•˜κ²Œ μ•Œ 수 μžˆλ‹€.
  • 이 λ©”μ„œλ“œλŠ” λ©”μ„œλ“œ 호좜 μ‹œ null둜 인해 λ°œμƒν•  수 μžˆλŠ” 문제λ₯Ό 사전에 방지할 수 μžˆλ„λ‘ 도와쀀닀.

3. λ§€κ°œλ³€μˆ˜λ₯Ό κ²€μ‚¬ν•˜λŠ” 방법 : λΉ„κ³΅κ°œ λ©”μ„œλ“œ

1) Java의 assert ꡬ문을 μ‚¬μš©ν•œ null 검사

κ³΅κ°œλ˜μ§€ μ•Šμ€ λ©”μ„œλ“œλΌλ©΄, νŒ¨ν‚€μ§€ μ œμž‘μžκ°€ 직접 λ©”μ„œλ“œκ°€ ν˜ΈμΆœλ˜λŠ” 상황을 ν†΅μ œ κ°€λŠ₯ν•˜κΈ° λ•Œλ¬Έμ— 였직 μœ νš¨ν•œ κ°’λ§Œμ΄ λ©”μ„œλ“œμ— λ„˜κ²¨μ§€λ¦¬λΌλŠ” 것을 보증해야 ν•œλ‹€.

즉, public 이 μ•„λ‹Œ λ©”μ„œλ“œλΌλ©΄ 단언문(assert)λ₯Ό μ‚¬μš©ν•΄ λ§€κ°œλ³€μˆ˜ μœ νš¨μ„±μ„ κ²€μ‚¬ν•˜μž. 핡심은 단언문듀이 μžμ‹ μ΄ λ‹¨μ–Έν•œ 쑰건이 무쑰건 참이라고 μ„ μ–Έν•œλ‹€λŠ” 것이닀.

Java의 assert ꡬ문을 μ‚¬μš©ν•˜μ—¬λ„ null 검사λ₯Ό μˆ˜ν–‰ν•  수 μžˆλ‹€. assertλŠ” νŠΉμ • 쑰건이 참인지 ν™•μΈν•˜λ©°, 쑰건이 거짓인 경우 AssertionErrorλ₯Ό λ˜μ§„λ‹€. μ΄λŠ” 주둜 디버깅 λͺ©μ μœΌλ‘œ μ‚¬μš©λ˜λ©°, λŸ°νƒ€μž„ μ‹œμ— ν™œμ„±ν™”ν•  수 μžˆλ‹€.

private static void sort(long a[], int offset, int length){
	assert a != null;
    assert offset >= 0 && offset <= a.length;
    assert length >= 0 && length <= a.length - offset;
    ...// 계산 μˆ˜ν–‰
}

πŸ”– 단언문(assert) νŠΉμ§•
1) μ‹€νŒ¨μ‹œ AssertionErrorλ₯Ό λ˜μ§„λ‹€.
2) λŸ°νƒ€μž„μ— μ•„λ¬΄λŸ° νš¨κ³Όλ„, μ•„λ¬΄λŸ° μ„±λŠ₯ μ €ν•˜λ„ μ—†λ‹€.

λ©”μ„œλ“œκ°€ 직접 μ‚¬μš©ν•˜μ§€ μ•ŠμœΌλ‚˜ λ‚˜μ€‘μ— μ“°λ €κ³  μ €μž₯ν•˜λŠ” λ§€κ°œλ³€μˆ˜μ˜ μœ νš¨μ„±μ€ λ”μš± μ‹ κ²½ μ¨μ„œ 검사해야 ν•œλ‹€. μƒμ„±μž λ§€κ°œλ³€μˆ˜μ˜ μœ νš¨μ„± κ²€μ‚¬λŠ”, 클래슀 λΆˆλ³€μ‹μ„ μ–΄κΈ°λŠ” 객체가 λ§Œλ“€μ–΄μ§€μ§€ μ•Šκ²Œ ν•˜λŠ”λ° κΌ­ ν•„μš”ν•˜λ‹€.

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class Item49Test {

    @Test
    public void requireNonNullTest2() {
        // null 값을 μ „λ‹¬ν•˜μ—¬ AssertionErrorκ°€ λ°œμƒν•˜λŠ”μ§€ 확인
        Assertions.assertThrows(AssertionError.class, () -> {
            nullTest2(null);
        });
    }

    public void nullTest2(Object obj) {
        // 객체가 null인지 검사, null이면 AssertionError λ°œμƒ
        assert obj != null;
    }
}
  • assert obj != null;: objκ°€ null이 μ•„λ‹Œμ§€ ν™•μΈν•˜λŠ” μ‘°κ±΄μž…λ‹ˆλ‹€. 쑰건이 λ§Œμ‘±λ˜μ§€ μ•ŠμœΌλ©΄ AssertionErrorκ°€ λ°œμƒ
  • Assertions.assertThrows()λ₯Ό 톡해 AssertionErrorκ°€ λ°œμƒν•˜λŠ”μ§€ ν…ŒμŠ€νŠΈν•œλ‹€.

assertλŠ” 주둜 개발 쀑에 μ‚¬μš©λ˜λ©°, ν”„λ‘œλ•μ…˜ ν™˜κ²½μ—μ„œλŠ” ν™œμ„±ν™”λ˜μ§€ μ•Šμ„ 수 μžˆλ‹€. 이 λ•Œλ¬Έμ— μ€‘μš”ν•œ μœ νš¨μ„± κ²€μ‚¬μ—λŠ” Objects.requireNonNull()κ³Ό 같은 λͺ…μ‹œμ μΈ 검사λ₯Ό μ‚¬μš©ν•˜λŠ” 것이 μ’‹λ‹€.

4. 였λ₯˜ κ²€μ‚¬μ˜ 일반 원칙 2: λ‚˜μ€‘μ— μ“°λ €κ³  μ €μž₯ν•˜λŠ” λ§€κ°œλ³€μˆ˜μ˜ μœ νš¨μ„± 검사

μ–΄λ–€ λ©”μ„œλ“œμ—μ„œ λ°˜ν™˜λœ 값을 λ‚˜μ€‘μ— μ‚¬μš©ν•˜κΈ° μœ„ν•΄ 보관할 λ•Œ, ν•΄λ‹Ή 값이 null인지 ν™•μΈν•˜μ§€ μ•ŠμœΌλ©΄ μ˜ˆμƒμΉ˜ λͺ»ν•œ 였λ₯˜κ°€ λ°œμƒν•  수 μžˆλ‹€.

λ‚˜μ€‘μ— 이 값이 nullμž„μ„ λ°œκ²¬ν•˜κ²Œ 되면 였λ₯˜μ˜ 원인을 μΆ”μ ν•˜λŠ” 것이 맀우 μ–΄λ €μšΈ 수 μžˆμœΌλ―€λ‘œ, μ €μž₯ν•˜κΈ° 전에 μœ νš¨μ„±μ„ κ²€μ‚¬ν•˜λŠ” 것이 μ€‘μš”ν•˜λ‹€.

μœ νš¨μ„± κ²€μ‚¬μ˜ μ€‘μš”μ„± μ˜ˆμ‹œ

λ§Œμ•½ μ–΄λ–€ λ©”μ„œλ“œμ—μ„œ λ°˜ν™˜λœ 객체λ₯Ό λ‚˜μ€‘μ— μ‚¬μš©ν•˜κΈ° μœ„ν•΄ μ €μž₯ν•΄ 두고, null인지 ν™•μΈν•˜μ§€ μ•Šμ€ 경우 μ˜ˆμƒμΉ˜ λͺ»ν•œ 였λ₯˜κ°€ λ°œμƒν•  수 μžˆλ‹€. 이λ₯Ό λ°©μ§€ν•˜κΈ° μœ„ν•΄ μ €μž₯ν•˜κΈ° 전에 μœ νš¨μ„±μ„ κ²€μ‚¬ν•˜λŠ” 것이 맀우 μ€‘μš”ν•˜λ‹€.

μ•„λž˜λŠ” μœ νš¨μ„± 검사λ₯Ό 톡해 null λ°©μ§€ν•˜λŠ” μ½”λ“œ μ˜ˆμ‹œ

import java.util.Objects;

public class UserManager {

    // μ‚¬μš©μž 정보λ₯Ό μ €μž₯ν•˜λŠ” λ©”μ„œλ“œ
    public void storeUser(User user) {
        // μ €μž₯ν•˜κΈ° 전에 μœ νš¨μ„± 검사 μˆ˜ν–‰
        Objects.requireNonNull(user, "User 객체가 nullμž…λ‹ˆλ‹€. μ €μž₯ν•  수 μ—†μŠ΅λ‹ˆλ‹€.");
        // μœ νš¨μ„± 검사 ν›„ μ•ˆμ „ν•˜κ²Œ 객체 μ €μž₯
        // ...
    }
    
    // User ν΄λž˜μŠ€λŠ” λ‹¨μˆœν•œ 데이터 객체둜 κ°€μ •
    static class User {
        String name;
        
        public User(String name) {
            this.name = name;
        }
    }
}
  • Objects.requireNonNull(user, "User 객체가 nullμž…λ‹ˆλ‹€. μ €μž₯ν•  수 μ—†μŠ΅λ‹ˆλ‹€."): μ‚¬μš©μž 객체가 null인지 κ²€μ‚¬ν•œλ‹€. 이둜 인해 μ €μž₯ν•˜κΈ° 전에 null 값을 λ°©μ§€ν•˜μ—¬ 예기치 μ•Šμ€ 였λ₯˜λ₯Ό μ˜ˆλ°©ν•  수 μžˆλ‹€.
  • 이λ₯Ό 톡해 λ‚˜μ€‘μ— null 포인터 문제둜 λ°œμƒν•  수 μžˆλŠ” 였λ₯˜λ₯Ό 미리 방지

일반 원칙 2의 μ˜ˆμ™Έ 상황

  1. μœ νš¨μ„± 검사 λΉ„μš©μ΄ μ§€λ‚˜μΉ˜κ²Œ λ†’κ±°λ‚˜ μ‹€μš©μ μ΄μ§€ μ•Šμ„ λ•Œ:
    • μœ νš¨μ„± 검사에 큰 λΉ„μš©μ΄ λ“ λ‹€λ©΄, μ‹€μš©μ μ΄μ§€ μ•Šμ„ 수 μžˆλ‹€.
  2. 계산 κ³Όμ •μ—μ„œ μ•”λ¬΅μ μœΌλ‘œ 검사가 μˆ˜ν–‰λ  λ•Œ:
    • 예λ₯Ό λ“€μ–΄, Collections.sort(List)의 경우 μ •λ ¬ κ³Όμ •μ—μ„œ νƒ€μž…μ˜ μœ νš¨μ„±μ΄ κ²€μ‚¬λœλ‹€. λ§Œμ•½ μƒν˜Έ 비ꡐ될 수 μ—†λŠ” νƒ€μž…μ΄ λ“€μ–΄ μžˆλ‹€λ©΄ ClassCastException을 λ˜μ§„λ‹€.
    • 암묡적 μœ νš¨μ„± 검사에 μ˜μ‘΄ν•˜λŠ” 것은 μ‹€νŒ¨ μ›μžμ„±(safety failure)을 ν•΄μΉ  수 μžˆμœΌλ―€λ‘œ μ£Όμ˜κ°€ ν•„μš”
      • μ‹€νŒ¨ μ›μžμ„±μ΄λž€, μœ νš¨μ„± 검사 μ‹€νŒ¨ 이후에도 객체의 μƒνƒœκ°€ λ³€ν•˜μ§€ μ•Šλ„λ‘ 보μž₯ν•˜λŠ” 것이닀. 즉, λ©”μ„œλ“œκ°€ μ—¬λŸ¬ 번 μ‹€νŒ¨ν•˜λ”λΌλ„ 항상 같은 κ²°κ³Όλ₯Ό λ°˜ν™˜ν•΄μ•Ό ν•œλ‹€. 예λ₯Ό λ“€μ–΄, 데이터λ₯Ό μΆ”κ°€ν•˜λŠ” 도쀑 였λ₯˜κ°€ λ°œμƒν•˜λ”λΌλ„ 데이터가 절반만 μΆ”κ°€λ˜λŠ” 상황을 λ°©μ§€ν•˜λŠ” 것이 μ‹€νŒ¨ μ›μžμ„±μ΄λ‹€.
import java.util.ArrayList;
import java.util.List;

public class ProductManager {
    private final List<String> products = new ArrayList<>();

    // μ œν’ˆ μΆ”κ°€ λ©”μ„œλ“œ
    public void addProduct(String product) {
        if (product == null) {
            throw new IllegalArgumentException("μ œν’ˆ 이름은 null이 될 수 μ—†μŠ΅λ‹ˆλ‹€.");
        }

        try {
            products.add(product);
        } catch (Exception e) {
            // 였λ₯˜ λ°œμƒ μ‹œ 리슀트λ₯Ό λ³€κ²½ν•˜κΈ° μ „ μƒνƒœλ‘œ 되돌리기
            products.remove(product);
            throw e; // μ˜ˆμ™Έλ₯Ό λ‹€μ‹œ 던짐
        }
    }

    public List<String> getProducts() {
        return new ArrayList<>(products); // 방어적 볡사
    }
}
  • addProduct(String product) λ©”μ„œλ“œλŠ” μ œν’ˆμ„ λ¦¬μŠ€νŠΈμ— μΆ”κ°€ν•˜λŠ” λ©”μ„œλ“œ
  • μ œν’ˆ 이름이 null이면 μ˜ˆμ™Έλ₯Ό λ˜μ§‘λ‹ˆλ‹€. μœ νš¨μ„± 검사λ₯Ό 톡해 null κ°’μœΌλ‘œ μΈν•œ 문제λ₯Ό λ°©μ§€ν•œλ‹€.

μΆ”κ°€ 도쀑 였λ₯˜κ°€ λ°œμƒν•˜λ©΄, λ¦¬μŠ€νŠΈμ—μ„œ ν•΄λ‹Ή μ œν’ˆμ„ μ œκ±°ν•˜μ—¬ 리슀트 μƒνƒœκ°€ λ³€κ²½λ˜μ§€ μ•Šλ„λ‘ ν•œλ‹€. μ΄λ ‡κ²Œ ν•¨μœΌλ‘œμ¨ μ‹€νŒ¨ μ›μžμ„±μ„ μœ μ§€ν•œλ‹€.

계산 쀑 λ˜μ Έμ§€λŠ” μ˜ˆμ™Έμ™€ API μ˜ˆμ™Έμ˜ 차이

  • 계산 쀑에 λ˜μ Έμ§€λŠ” μ˜ˆμ™Έμ™€ APIμ—μ„œ λ˜μ§€κΈ°λ‘œ ν•œ μ˜ˆμ™Έκ°€ λ‹€λ₯Ό 수 μžˆλ‹€.
  • 이 경우 μ €μˆ˜μ€€ μ˜ˆμ™Έλ₯Ό μž‘μ•„ κ³ μˆ˜μ€€μ˜ μ‚¬μš©μž μ •μ˜ μ˜ˆμ™Έλ‘œ λ³€ν™˜ν•˜λŠ” μ˜ˆμ™Έ λ²ˆμ—­(exception translation)이 ν•„μš”ν•˜λ‹€.
    • 예λ₯Ό λ“€μ–΄, λ‚΄λΆ€μ μœΌλ‘œ λ°œμƒν•˜λŠ” ClassCastException을 더 의미 μžˆλŠ” InvalidDataExceptionκ³Ό 같은 μ‚¬μš©μž μ •μ˜ μ˜ˆμ™Έλ‘œ λ³€ν™˜ν•˜μ—¬ μ œκ³΅ν•  수 μžˆλ‹€.

계산 쀑에 λ˜μ Έμ§€λŠ” μ €μˆ˜μ€€ μ˜ˆμ™Έμ™€ APIμ—μ„œ λ˜μ§€κΈ°λ‘œ ν•œ κ³ μˆ˜μ€€ μ˜ˆμ™Έκ°€ λ‹€λ₯Ό 수 μžˆλ‹€. μ΄λ•ŒλŠ” μ €μˆ˜μ€€ μ˜ˆμ™Έλ₯Ό μž‘μ•„ 의미 μžˆλŠ” κ³ μˆ˜μ€€ μ‚¬μš©μž μ •μ˜ μ˜ˆμ™Έλ‘œ λ³€ν™˜ν•΄μ£ΌλŠ” μ˜ˆμ™Έ λ²ˆμ—­(exception translation)이 ν•„μš”

import java.util.List;

public class DataService {

    // 데이터λ₯Ό κ²€μƒ‰ν•˜λŠ” λ©”μ„œλ“œ
    public String findData(List<String> data, int index) {
        try {
            // 인덱슀λ₯Ό 톡해 데이터λ₯Ό 검색
            return data.get(index);
        } catch (IndexOutOfBoundsException e) {
            // μ €μˆ˜μ€€ μ˜ˆμ™ΈμΈ IndexOutOfBoundsException을 μ‚¬μš©μž μ •μ˜ μ˜ˆμ™Έλ‘œ λ³€ν™˜
            throw new DataNotFoundException("데이터 μΈλ±μŠ€κ°€ 잘λͺ»λ˜μ—ˆμŠ΅λ‹ˆλ‹€: " + index, e);
        }
    }

    // μ‚¬μš©μž μ •μ˜ μ˜ˆμ™Έ
    public static class DataNotFoundException extends RuntimeException {
        public DataNotFoundException(String message, Throwable cause) {
            super(message, cause);
        }
    }

    public static void main(String[] args) {
        DataService service = new DataService();
        List<String> data = List.of("apple", "banana", "cherry");

        try {
            // 잘λͺ»λœ 인덱슀λ₯Ό μ „λ‹¬ν•˜μ—¬ μ˜ˆμ™Έ λ°œμƒ
            service.findData(data, 5);
        } catch (DataNotFoundException e) {
            System.err.println("였λ₯˜ λ°œμƒ: " + e.getMessage());
        }
    }
}
  • findData(List<String> data, int index) λ©”μ„œλ“œλŠ” 주어진 μΈλ±μŠ€μ—μ„œ 데이터λ₯Ό κ²€μƒ‰ν•œλ‹€.
  • λ§Œμ•½ μΈλ±μŠ€κ°€ 잘λͺ»λ˜λ©΄ IndexOutOfBoundsException이 λ°œμƒν•œλ‹€. 이 μ˜ˆμ™Έλ₯Ό κ·ΈλŒ€λ‘œ λ˜μ§€λŠ” λŒ€μ‹ , DataNotFoundExceptionμ΄λΌλŠ” μ‚¬μš©μž μ •μ˜ μ˜ˆμ™Έλ‘œ λ³€ν™˜
  • μ΄λ ‡κ²Œ μ €μˆ˜μ€€ μ˜ˆμ™Έλ₯Ό κ³ μˆ˜μ€€ μ˜ˆμ™Έλ‘œ λ²ˆμ—­ν•˜μ—¬ 더 의미 μžˆλŠ” 정보λ₯Ό μ œκ³΅ν•  수 μžˆλ‹€.

DataNotFoundException은 κ³ μˆ˜μ€€ μ˜ˆμ™Έλ‘œ, μ˜ˆμ™Έ λ©”μ‹œμ§€λ₯Ό 톡해 λ¬Έμ œκ°€ 무엇인지 더 λͺ…ν™•ν•˜κ²Œ μ•Œ 수 μžˆλ‹€.

5. μ˜ˆμ™Έ

λ©”μ„œλ“œ λͺΈμ²΄ μ‹€ν–‰ 전에 λ§€κ°œλ³€μˆ˜ μœ νš¨μ„±μ„ 검사해야 ν•œλ‹€λŠ” κ·œμΉ™μ—λ„ μ˜ˆμ™ΈλŠ” μ‘΄μž¬ν•œλ‹€. λ°”λ‘œ, μœ νš¨μ„± 검사 λΉ„μš©μ΄ μ§€λ‚˜μΉ˜κ²Œ λ†’κ±°λ‚˜ μ‹€μš©μ μ΄μ§€ μ•Šμ„ λ•Œ, ν˜Ήμ€ 계산 κ³Όμ •μ—μ„œ μ•”λ¬΅μ μœΌλ‘œ 검사가 μˆ˜ν–‰λ  λ•Œμ΄λ‹€.

예λ₯Ό λ“€μ–΄ ν›„μžμ˜ 경우, Collections.sort(List) 처럼 객체 리슀트λ₯Ό μ •λ ¬ν•˜λŠ” λ©”μ„œλ“œλ₯Ό 생각해보면 리슀트 μ•ˆμ˜ 객체듀은 λͺ¨λ‘ μƒν˜Έ λΉ„κ΅λ˜μ–΄ μžˆμ–΄μ•Ό ν•˜λ©° 비ꡐ될 수 μ—†λŠ” νƒ€μž…μ˜ 객체가 λ“€μ–΄μžˆλ‹€λ©΄ ClassCastException을 λ˜μ§„λ‹€. ν•˜μ§€λ§Œ 암묡적 μœ νš¨μ„± 검사에 λ„ˆλ¬΄ μ˜μ‘΄ν•œλ‹€λ©΄ μ‹€νŒ¨ μ›μžμ„±(μ•„μ΄ν…œ 76)을 ν•΄μΉ  수 μžˆμœΌλ‹ˆ μ£Όμ˜ν•˜μž.

πŸ“š 핡심 정리

λ©”μ„œλ“œλ‚˜ μƒμ„±μžλ₯Ό μž‘μ„±ν•  λ•ŒλŠ” λ§€κ°œλ³€μˆ˜λ“€μ— μ–΄λ– ν•œ μ œμ•½μ΄ μžˆμ„ 지 생각해야 ν•œλ‹€.

κ·Έ μ œμ•½λ“€μ„ λ¬Έμ„œν™”ν•˜κ³  λ©”μ„œλ“œ μ½”λ“œ μ‹œμž‘ λΆ€λΆ„μ—μ„œ λͺ…μ‹œμ μœΌλ‘œ κ²€μ‚¬ν•˜λ©΄, μœ νš¨μ„± 검사가 μ‹€μ œ 였λ₯˜λ₯Ό 처음 κ±ΈλŸ¬λ‚Ό λ•Œ 효과λ₯Ό λ³Ό 것이닀.

  • μ—λŸ¬κ°€ λ‚ λ§Œν•œ 뢀뢄을 미리 κ±ΈλŸ¬λ‚΄μ„œ λ‚˜μ€‘μ— λ³΅μž‘ν•œ μ—λŸ¬λ₯Ό λ§Œλ“€μ§€ 말자.

단, λ¬΄μž‘μ • λ§€κ°œλ³€μˆ˜μ— λ§Žμ€ μ œμ•½μ„ 걸진 말자. λ©”μ„œλ“œλŠ” μ΅œλŒ€ν•œ λ²”μš©μ μœΌλ‘œ μž‘μ„±λ˜λŠ” 것이 λ§žλ‹€.

  • λ©”μ„œλ“œ μž‘μ„± μ‹œ, λ§€κ°œλ³€μˆ˜μ˜ μœ νš¨μ„± κ²€μ‚¬λŠ” λ°˜λ“œμ‹œ ν•„μš”ν•©λ‹ˆλ‹€. 특히 null 검사λ₯Ό 톡해 μ˜ˆμƒμΉ˜ λͺ»ν•œ NullPointerException을 λ°©μ§€ν•˜κ³ , 더 κ²¬κ³ ν•œ μ½”λ“œλ₯Ό μž‘μ„±ν•  수 μžˆλ‹€.
  • Java의 assertλŠ” 개발 쀑 디버깅 λͺ©μ μœΌλ‘œλŠ” μœ μš©ν•˜μ§€λ§Œ, ν”„λ‘œλ•μ…˜ ν™˜κ²½μ—μ„œμ˜ μœ νš¨μ„± κ²€μ‚¬μ—λŠ” μ ν•©ν•˜μ§€ μ•Šλ‹€. λ”°λΌμ„œ μ€‘μš”ν•œ κ²€μ‚¬μ—λŠ” Objects.requireNonNull()κ³Ό 같은 λͺ…μ‹œμ μΈ 방식을 μ‚¬μš©ν•˜λŠ” 것이 μ’‹λ‹€.
  • λ§€κ°œλ³€μˆ˜ μœ νš¨μ„± 검사 μ‹œ λΉ„μš©κ³Ό μ‹€μš©μ„±μ„ ν•¨κ»˜ κ³ λ €ν•˜κ³ , 무쑰건 λͺ¨λ“  경우λ₯Ό κ²€μ‚¬ν•˜κΈ°λ³΄λ‹€λŠ” ν•„μš”ν•œ κ²½μš°μ—λ§Œ μ μš©ν•˜μ—¬ 효율적인 μ½”λ“œλ₯Ό μž‘μ„±ν•˜λŠ” 것이 μ’‹λ‹€.

좜처 및 μ°Έκ³