λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

πŸ“šμ½μ€ μ±… 정리/μ΄νŽ™ν‹°λΈŒμžλ°”

[μ΄νŽ™ν‹°λΈŒ μžλ°”] 8μž₯ : λ©”μ„œλ“œ

λ©”μ„œλ“œμ˜ λ§€κ°œλ³€μˆ˜μ™€ λ°˜ν™˜κ°’μ€ μ–΄λ–»κ²Œ μ²˜λ¦¬ν•˜λŠ”μ§€

λ©”μ„œλ“œ μ‹œκ·Έλ‹ˆμ²˜λŠ” μ–΄λ–»κ²Œ 섀계 ν•΄μ•Ό ν•˜λŠ”μ§€

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

λ©”μ„œλ“œμ™€ μƒμ„±μž λŒ€λΆ€λΆ„μ€ μž…λ ₯ λ§€κ°œλ³€μˆ˜ 값이 νŠΉμ • 쑰건을 λ§Œμ‘±ν•˜κΈ°λ₯Ό λ°”λž€λ‹€.

  • 예λ₯Ό λ“€μ–΄ 인덱슀 값은 음수둜 λ„˜μ–΄μ˜€λ©΄ μ•ˆλ˜κ³ , κ°μ²΄μ°Έμ‘°λŠ” null이 μ•„λ‹ˆμ—¬μ•Όλ§Œ ν•œλ‹€.

λ˜ν•œ 잘λͺ»λ˜μ—ˆμ„ λ•Œ λ°œμƒν•˜λŠ” μ˜ˆμ™Έλ₯Ό λ¬Έμ„œν™”ν•˜μ—¬ λ‚¨κ²¨λ†”μ•Όν•œλ‹€.

requiredNonNullκ³Ό assertλ₯Ό 톡해 λ§€κ°œλ³€μˆ˜ μœ νš¨μ„± 검사λ₯Ό ν•  수 도 μžˆλ‹€.

μœ νš¨μ„± 검사λ₯Ό 톡해 후에 생길 수 μžˆλŠ” μ—λŸ¬λ₯Ό 쑰기에 찾을 수 μžˆλ‹€.

  • λ©”μ„œλ“œλŠ” μ΅œλŒ€ν•œ λ²”μš©μ μœΌλ‘œ μ„€κ³„ν•˜λΌ. μ œμ•½μœΌλ‘œ 인해 본래의 κΈ°λŠ₯을 λͺ»ν•΄μ„œλŠ” μ•ˆλœλ‹€.

μ•„μ΄ν…œ 50 : μ μ‹œμ— 방어적 볡사본을 λ§Œλ“€λΌ

ν΄λΌμ΄μ–ΈνŠΈκ°€ λΆˆλ³€μ‹μ„ κΉ¨λœ¨λ¦¬λ €ν•œλ‹€κ³  μƒκ°ν•˜κ³  ‘λ°©μ–΄μ μœΌλ‘œ ν”„λ‘œκ·Έλž˜λ°' 해라.

λΆˆλ³€ 객체 내뢀에 κ°€λ³€ 객체 멀버λ₯Ό 가진 경우

public Period(Date start, Date end) {
        if (start.compareTo(end) > 0)
            throw new IllegalArgumentException(
                    start + "κ°€ " + end + "보닀 λŠ¦λ‹€.");
        this.start = start;
        this.end   = end;
    }

    public Date start() {
        return start;
    }
    public Date end() {
        return end;
    }

    public String toString() {
        return start + " - " + end;
    }

λ‚΄λΆ€μ˜ κ°€λ³€ 객체둜 인해 μ™ΈλΆ€μ—μ„œ λΆˆλ³€μ‹μ΄ λ¬΄λ„ˆμ§ˆ 수 μžˆλ‹€. (Date())

이λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄μ„œλŠ”

  1. κ°€λ³€ λ‚΄λΆ€ 객체λ₯Ό λΆˆλ³€ 객체둜 λ³€ν™”μ‹œν‚€κΈ° (μžλ°” 8의 λΆˆλ³€ λ‚΄λΆ€ 객체 μ‚¬μš©ν•΄μ„œ ν•΄κ²° LocalDateTime)
  2. κ°€λ³€ λ‚΄λΆ€ 객체λ₯Ό λŒ€μ‹ ν•  볡사본을 λ§Œλ“€μ–΄μ„œ κ°μ²΄μ—μ„œ μ‚¬μš©ν•˜κΈ° (외뢀와 객체λ₯Ό κ³΅μœ ν•˜μ§€ μ•ŠμŒ)
  • ν•΄κ²° μ½”λ“œ
		public Period(Date start, Date end) {
        this.start = new Date(start.getTime());
        this.end   = new Date(end.getTime());

        if (this.start.compareTo(this.end) > 0)
            throw new IllegalArgumentException(
                    this.start + "κ°€ " + this.end + "보닀 λŠ¦λ‹€.");
    }

    // μ½”λ“œ 50-5 μˆ˜μ •ν•œ μ ‘κ·Όμž - ν•„λ“œμ˜ 방어적 볡사본을 λ°˜ν™˜ν•œλ‹€. (305μͺ½)
    public Date start() {
        return new Date(start.getTime());
    }

    public Date end() {
        return new Date(end.getTime());
    }

-핡심정리-

ν΄λΌμ΄μ–ΈνŠΈλ‘œλΆ€ν„° λ°›λŠ” μš”μ†Œ, λ°˜ν™˜ μš”μ†Œκ°€ 가변이라면 λ°˜λ“œμ‹œ λ°©μ–΄μ μœΌλ‘œ λ³΅μ‚¬ν•˜μž.

λ§Œμ•½, λΉ„μš©μ΄ ν¬κ±°λ‚˜ μ‚¬μš©μžλ₯Ό μ‹ λ’°ν•œλ‹€λ©΄ 방어적 λ³΅μ‚¬λŒ€μ‹  μš”μ†Œ μˆ˜μ • μ‹œ μ±…μž„μ΄ μ‚¬μš©μžμ—κ²Œ μžˆμŒμ„ λͺ…μ‹œν•΄λ‘μž.

μ•„μ΄ν…œ 51 : λ©”μ„œλ“œ μ‹œκ·Έλ‹ˆμ²˜λ₯Ό μ‹ μ€‘νžˆ μ„€κ³„ν•˜λΌ

API 섀계 μš”λ Ή

  1. λ©”μ„œλ“œ 이름을 μ‹ μ€‘νžˆ μ§“μž
    1. 같은 νŒ¨ν‚€μ§€μ— μ†ν•œ 이름과 μΌκ΄€λ˜κ²Œ 짓고 μžλ°” 라이브러리 κ°€μ΄λ“œ μ°Έμ‘°ν•  것
  2. 편의 λ©”μ„œλ“œλ₯Ό λ„ˆλ¬΄ 많이 λ§Œλ“€μ§€ 말자
    1. λ©”μ„œλ“œκ°€ 많으면 κ΅¬ν˜„ν•˜λŠ” μ‚¬λžŒ μ‚¬μš©ν•˜λŠ” μ‚¬λžŒ λͺ¨λ‘ νž˜λ“€λ‹€. 확신이 μ—†λ‹€λ©΄ λ§Œλ“€μ§€ 말자
  3. λ§€κ°œλ³€μˆ˜ λͺ©λ‘μ€ 짧게 μœ μ§€ν•˜μž.
    1. 같은 νƒ€μž…μ˜ λ§€κ°œλ³€μˆ˜κ°€ 연달아 λ‚˜μ˜€λŠ” 경우 특히 ν•΄λ‘­λ‹€ (각각의 λœ»μ„ μ΄ν•΄ν•˜κΈ° μ–΄λ €μ›Œμ§)
    • λ©”μ„œλ“œ μͺΌκ°œκΈ°, 헬퍼 클래슀, λΉŒλ” νŒ¨ν„΄ μ‚¬μš©ν•΄μ„œ 짧게 λ§Œλ“€μž
  4. λ§€κ°œλ³€μˆ˜ νƒ€μž…μœΌλ‘œλŠ” ν΄λž˜μŠ€λ³΄λ‹€ μΈν„°νŽ˜μ΄μŠ€κ°€ λ‚«λ‹€
    1. 훨씬 λ²”μš©μ μœΌλ‘œ 인자λ₯Ό λ°›μ•„μ˜¬ 수 μžˆλ‹€. μΈν„°νŽ˜μ΄μŠ€ μžμ‹κ³Ό 이후에 λ§Œλ“€μ–΄μ§ˆ κ°μ²΄λ“€κΉŒμ§€λ„ κ°€λŠ₯!! λ§Œμ•½ 클래슀λ₯Ό μ‚¬μš©ν•œλ‹€λ©΄ λ©”μ„œλ“œ μ‚¬μš©μ„ μœ„ν•΄ νŠΉμ • 클래슀둜의 볡사 λΉ„μš©μ„ μΉ˜λ€„μ•Ό ν•œλ‹€.
  5. booleanλ³΄λ‹€λŠ” μ›μ†Œ 2개짜리 μ—΄κ±° νƒ€μž…μ΄ λ‚«λ‹€.
    1. λ¬Όλ‘ , λ©”μ„œλ“œ 이름상 boolean 더 λͺ…ν™•ν•œ κ²½μš°λŠ” μ˜ˆμ™Έ
    2. μ—΄κ±° νƒ€μž…μ΄ μ½”λ“œλ₯Ό 읽기 더 쉽고 λ‚˜μ€‘μ— 선택지λ₯Ό μΆ”κ°€ν•˜κΈ°λ„ 쉽닀.μ˜¨λ„κ³„ 클래슀의 정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œκ°€ 이 μ—΄κ±° νƒ€μž…μ„ μž…λ ₯λ°›μ•„ μ ν•©ν•œ μ˜¨λ„κ³„ μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•œλ‹€κ³  ν•΄λ³΄μž.
    3. ‘Thermometer.newInstance(true)’ λ³΄λ‹€λŠ” ‘Thermometer.newInstance(TemperatureScale.CELSIUS)’ κ°€ 훨씬 λͺ…ν™•ν•˜λ‹€.
    4. public enum TemperatureScale { FAHRENHEIT, CELSIUS }

μ•„μ΄ν…œ 52 : λ‹€μ€‘μ •μ˜λŠ” μ‹ μ€‘νžˆ μ‚¬μš©ν•˜λΌ

λ‹€μ€‘μ •μ˜(μ˜€λ²„λ‘œλ”©) λ©”μ„œλ“œ 쀑 μ–΄λŠ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν• μ§€λŠ” μ»΄νŒŒμΌνƒ€μž„μ— κ²°μ •λœλ‹€.

public class CollectionClassifier {
  	public static String classify(Set<?> s) {
      	return "집합";
    }
  	
  	public static String classify(Collection<?> c) {
      	return "κ·Έ μ™Έ";
    }
  
  	public static void main(String[] args) {
      	Collection<?>[] collections = { new Hashset<String>(), new ArrayList<String>() };
      
      	for (Collection<?> c : collections)
          	System.out.println(classify(c)); // "κ·Έ μ™Έ  κ·Έ μ™Έ" μ»΄νŒŒμΌνƒ€μž„μ— λ©”μ„œλ“œ κ²°μ •
    }
}

λ”°λΌμ„œ μΈμˆ˜κ°€ μ»¬λ ‰μ…˜μΌ λ•Œ μ–΄λ–€ λ©”μ„œλ“œκ°€ μ‹€ν–‰λ μ§€λŠ” 컴파일 νƒ€μž„μ— κ²°μ •λ˜κ²Œ 되고 μ–΄λ–€ κ΅¬ν˜„μ²΄μΈμ§€μ— 상관없이 “κ·Έ μ™Έ"값이 λ‚˜μ˜€κ²Œ λœλ‹€.

μž¬μ •μ˜(μ˜€λ²„λΌμ΄λ”©)은 이와 달리 λŸ°νƒ€μž„μ— λ™μ μœΌλ‘œ λ©”μ„œλ“œκ°€ μ„ νƒλœλ‹€.

class Wine {
  	String name() { return "와인"; }
}

class SparklingWine extends Wine {
  @Override String name() { return "μŠ€νŒŒν΄λ§μ™€μΈ"; }
}

public class Overriding {
  	public static void main(String[] args) {
      	List<Wine> wineList = List.of(new Wine(), new SparklingWine());
      
      	for (Wine wine : wineList) {
          	System.out.println(wine.name()); // "와인 μŠ€νŒŒν΄λ§μ™€μΈ" κ°€μž₯ ν•˜μœ„μ—μ„œ μ •μ˜ν•œ λ©”μ„œλ“œ 호좜
        }
    }
}

각각의 νƒ€μž…μ— 맞게 μ •μ˜ν•œ λ©”μ„œλ“œκ°€ μ‹€ν–‰λ˜κ²Œ λœλ‹€.

λ‹€μ€‘μ •μ˜κ°€ ν˜Όλˆμ„ μΌμœΌν‚€λŠ” 상황을 ν”Όν•˜μž.

  • λ§€κ°œλ³€μˆ˜ μˆ˜κ°€ 같은 μ˜€λ²„λ‘œλ”©μ€ ν•˜μ§€λ§μž
  • κ°€λ³€μΈμˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” λ©”μ„œλ“œλŠ” μ•„μ˜ˆ λ‹€μ€‘μ •μ˜ ν•˜μ§€λ§μž
  • μ˜€λ²„λ‘œλ”© λŒ€μ‹  λ©”μ„œλ“œ 이름을 λ‹€λ₯΄κ²Œ μ§€μ–΄μ£Όμž

μ•„μ΄ν…œ 53 : κ°€λ³€μΈμˆ˜λŠ” μ‹ μ€‘νžˆ μ‚¬μš©ν•˜λΌ

인수의 갯수λ₯Ό λ‹Ήμž₯ μ •ν•  순 μ—†μ§€λ§Œ ν•˜λ‚˜μ΄μƒ λ°›λŠ” 것을 보μž₯λ°›κ³  μ‹Άλ‹€λ©΄ μ•„λž˜μ²˜λŸΌ ν•˜λΌ

static int min(int firstArg, int... remainingArgs) { // ν•˜λ‚˜ μ΄μƒμ˜ λ§€κ°œλ³€μˆ˜λ₯Ό λ°›μ•„μ•Ό 함
  	int min = firstArg;
  	for (int arg : remainingArgs)
      	if (arg < min)
          	min = arg;
    return min;
}

κ°€λ³€ 인수λ₯Ό μ‚¬μš©ν•˜λ©΄ μ„±λŠ₯이 μ•ˆμ’‹μ•„μ§ˆ 수 μžˆλ‹€. 많이 μ“°λŠ” κ²½μš°κΉŒμ§€ μ˜€λ²„λ‘œλ”©μ„ 톡해 인수 갯수λ₯Ό 보μž₯ν•΄μ£Όκ³  적은 μ‚¬μš©κΉŒμ§€ 보μž₯ν•˜κΈ° μœ„ν•΄ κ°€λ³€ 인수λ₯Ό μ‚¬μš©ν•˜λ©΄ νŠΉμˆ˜μƒν™©λ„ ν•΄κ²° κ°€λŠ₯ν•˜λ‹€.

μ•„μ΄ν…œ 54 : null이 μ•„λ‹Œ, 빈 μ»¬λ ‰μ…˜μ΄λ‚˜ 배열을 λ°˜ν™˜ν•˜λΌ

λ§Œμ•½ μ»¬λ ‰μ…˜μ΄λ‚˜ 배열이 λΉ„μ–΄μžˆλ‹€λ©΄ null이 μ•„λ‹Œ 빈 객체λ₯Ό λ°˜ν™˜ν•˜λΌ.

null을 λ°˜ν™˜ν•˜λ©΄ 이λ₯Ό λ°›λŠ” μͺ½μ—μ„œ null인지 κ²€μ‚¬ν•˜λŠ” λ°©μ–΄ μ½”λ“œκ°€ ν•„μš”ν•˜κ³  이λ₯Ό 빼먹으면 였λ₯˜κ°€ λ°œμƒν•œλ‹€.

null을 λ°˜ν™˜ν•˜λŠ” APIλŠ” μ‚¬μš©ν•˜κΈ° μ–΄λ ΅κ³  였λ₯˜ 처리 μ½”λ“œλ„ λŠ˜μ–΄λ‚œλ‹€.

μ•„μ΄ν…œ 55 : μ˜΅μ…”λ„ λ°˜ν™˜μ€ μ‹ μ€‘νžˆ ν•˜λΌ

μ˜΅μ…”λ„μ€ μ›μ†Œλ₯Ό μ΅œλŒ€ 1개 κ°€μ§ˆ 수 μžˆλŠ” λΆˆλ³€ μ»¬λ ‰μ…˜μ΄λ‹€.

μ˜ˆμ™Έλ₯Ό λ˜μ§€λŠ” λ©”μ„œλ“œλ³΄λ‹€ μœ μ—°ν•˜κ³  μ‚¬μš©ν•˜κΈ° μ‰¬μš°λ©°, null을 λ°˜ν™˜ν•˜λŠ” λ©”μ„œλ“œλ³΄λ‹€ 였λ₯˜ κ°€λŠ₯성이 μž‘λ‹€.

μ˜΅μ…”λ„μ„ λ°˜ν™˜ν•˜λŠ” λ©”μ„œλ“œμ—μ„œλŠ” μ ˆλŒ€ null을 λ°˜ν™˜ν•˜μ§€ 말자.

public static <E extends Comparable<E>>
    Optional<E> max(Collection<E> c) {
        if (c.isEmpty())
            return Optional.empty();

        E result = null;
        for (E e : c)
            if (result == null || e.compareTo(result) > 0)
                result = Objects.requireNonNull(e);

        return Optional.of(result);
    }

μ˜΅μ…”λ„ 정적 νŒ©ν„°λ¦¬λ₯Ό μ‚¬μš©ν•˜μ—¬ λ°˜ν™˜.

μ˜΅μ…”λ„μ€ 검사 μ˜ˆμ™Έμ™€ 취지가 λΉ„μŠ·ν•˜λ‹€

  • λ°˜ν™˜κ°’μ΄ 없을 μˆ˜λ„ μžˆμŒμ„ APIμ‚¬μš©μžμ—κ²Œ μ•Œλ €μ€€λ‹€.
  • ν΄λΌμ΄μ–ΈνŠΈμ—κ²Œ 값을 받지 λͺ»ν–ˆμ„ λ•Œ μ·¨ν•  행동을 μž‘μ„±ν•˜λ„λ‘ ν•œλ‹€.

μ»¬λ ‰μ…˜, 슀트림, λ°°μ—΄, μ˜΅μ…”λ„ 같은 μ»¨ν…Œμ΄λ„ˆ νƒ€μž…μ€ μ˜΅μ…”λ„λ‘œ κ°μ‹Έμ§€λ§μž

  • λŒ€μ‹  빈 μ»¨ν…Œμ΄λ„ˆλ₯Ό λ°˜ν™˜ν•˜μž.

λ°˜ν™˜ νƒ€μž…μ„ Optional<T>둜 ν•΄μ•Όν•˜λŠ” 경우

  • κ²°κ³Όκ°€ 없을 수 있으며, ν΄λΌμ΄μ–ΈνŠΈκ°€ 이 상황을 νŠΉλ³„νžˆ μ²˜λ¦¬ν•΄μ•Όν•˜λŠ” 경우

λ°•μ‹±νƒ€μž…μ€ μ„±λŠ₯이 μ•ˆμ’‹μ•„μ§€λŠ” Optional에 담지말고 κΈ°λ³Ένƒ€μž…μ„ μ‚¬μš©ν•˜μž.

-핡심정리-

μ˜΅μ…”λ„μ€ 거의 λ°˜ν™˜κ°’μœΌλ‘œ μ‚¬μš©ν•˜κ³  μ΄μ™Έμ˜ μš©λ„λŠ” 잘 μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€. μ„±λŠ₯ μ΄μŠˆκ°€ μžˆμ„ 수 μžˆμœΌλ‹ˆ μ‹ μ€‘νžˆ μ‚¬μš©ν•˜μž.

μ•„μ΄ν…œ 56 : 곡개된 API μš”μ†Œμ—λŠ” 항상 λ¬Έμ„œν™” 주석을 μž‘μ„±ν•˜λΌ

APIλ₯Ό μ˜¬λ°”λ‘œ λ¬Έμ„œν™”ν•˜λ €λ©΄ 곡개된 λͺ¨λ“  클래슀, μΈν„°νŽ˜μ΄μŠ€, λ©”μ„œλ“œ, ν•„λ“œ 선언에 λ¬Έμ„œν™” 주석을 달아야 ν•œλ‹€.

ν‘œμ€€ κ·œμ•½μ„ μΌκ΄€λ˜κ²Œ μ§€ν‚€μž.