item 17 Jung inchul - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki

Effective Java 3e μ•„μ΄ν…œ 17λ₯Ό μš”μ•½ν•œ λ‚΄μš© μž…λ‹ˆλ‹€.

λΆˆλ³€ ν΄λž˜μŠ€λŠ” κ°€λ³€ ν΄λž˜μŠ€λ³΄λ‹€ μ„€κ³„ν•˜κ³  κ΅¬ν˜„ν•˜κ³  μ‚¬μš©ν•˜κΈ° μ‰¬μš°λ©°, 였λ₯˜κ°€ 생길 여지도 적고 훨씬 μ•ˆμ „ν•˜λ‹€.

클래슀λ₯Ό λΆˆλ³€μœΌλ‘œ λ§Œλ“€λ €λ©΄ λ‹€μŒ λ‹€μ„― 가지 κ·œμΉ™μ„ λ”°λ₯΄λ©΄ λœλ‹€.

  • 객체의 μƒνƒœλ₯Ό λ³€κ²½ν•˜λŠ” λ©”μ„œλ“œ(λ³€κ²½μž)λ₯Ό μ œκ³΅ν•˜μ§€ μ•ŠλŠ”λ‹€.
  • 클래슀λ₯Ό ν™•μž₯ν•  수 없도둝 ν•œλ‹€. 상속을 λ§‰λŠ” λŒ€ν‘œμ μΈ 방법은 클래슀λ₯Ό final둜 μ„ μ–Έν•˜λŠ” κ²ƒμ΄μ§€λ§Œ, λ‹€λ₯Έ 방법도 뒀에 μ‚΄νŽ΄λ³Ό 것이닀.
  • λͺ¨λ“  ν•„λ“œλ₯Ό final둜 μ„ μ–Έν•œλ‹€.
  • λͺ¨λ“  ν•„λ“œλ₯Ό private으둜 μ„ μ–Έν•œλ‹€.
  • μžμ‹  μ™Έμ—λŠ” λ‚΄λΆ€μ˜ κ°€λ³€ μ»΄ν¬λ„ŒνŠΈμ— μ ‘κ·Όν•  수 없도둝 ν•œλ‹€. 이런 ν•„λ“œλŠ” μ ˆλŒ€ ν΄λΌμ΄μ–ΈνŠΈκ°€ μ œκ³΅ν•œ 객체 μ°Έμ‘°λ₯Ό κ°€λ¦¬ν‚€κ²Œ ν•΄μ„œλŠ” μ•ˆ 되며, μ ‘κ·Όμž λ©”μ„œλ“œκ°€ κ·Έ ν•„λ“œλ₯Ό κ·ΈλŒ€λ‘œ λ°˜ν™˜ν•΄μ„œλ„ μ•ˆ λœλ‹€. μƒμ„±μž, μ ‘κ·Όμž, readObject λ©”μ„œλ“œ λͺ¨λ‘μ—μ„œ 방어적 볡사λ₯Ό μˆ˜ν–‰ν•˜λΌ
    public final class Complex {
    	private final double re;
    	private final double im;
    
    	public Complex(double re, double im) {
    		this.re = re;
    		this.im = im;
    	}
    
    	...
    
    	public Complex plus(Complex c) {
    		return new Complex(re + c.re, im + c.im);
    	}
    
    	public Complex minus(Complex c) {
    		return new Complex(re - c.re, im - c.im);
    	}
    
    	public Complex times(Complex c) {
    		return new Complex(re * c.re - im * c.im, re * c.im + im. * c.re);
    	}
    
    	@Override public boolean equals(Object o) {
    		if (o == this)
    			return true;
    		if (!(o instanceof Complex))
    			return false;
    		Complex c = (Complex) o;
    
    		return Double.compare(c.re, re) == 0
    						&& Double.compare(c.im, im);
    	}

이 사칙연산 λ©”μ„œλ“œλ“€μ΄ μΈμŠ€ν„΄μŠ€ μžμ‹ μ€ μˆ˜μ •ν•˜μ§€ μ•Šκ³  μƒˆλ‘œμš΄ Complex μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€μ–΄ λ°˜ν™˜ν•˜λŠ” λͺ¨μŠ΅μ— μ£Όλͺ©ν•˜μž. 이처럼 ν”Όμ—°μ‚°μžμ— ν•¨μˆ˜λ₯Ό μ μš©ν•΄ κ·Έ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•˜μ§€λ§Œ ν”Όμ—°μ‚°μž μžμ²΄λŠ” κ·ΈλŒ€λ‘œμΈ ν”„λ‘œκ·Έλž˜λ° νŒ¨ν„΄μ„ ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ΄λΌ ν•œλ‹€. 이와 달리, 절차적 ν˜Ήμ€ λͺ…λ Ήν˜• ν”„λ‘œκ·Έλž˜λ°μ—μ„œλŠ” λ©”μ„œλ“œμ—μ„œ ν”Όμ—°μ‚°μžμΈ μžμ‹ μ„ μˆ˜μ •ν•΄ μžμ‹ μ˜ μƒνƒœκ°€ λ³€ν•˜κ²Œ λœλ‹€.

λΆˆλ³€ κ°μ²΄λŠ” 근본적으둜 μŠ€λ ˆλ“œ μ•ˆμ „ν•˜μ—¬ λ”°λ‘œ 동기화할 ν•„μš” μ—†κΈ° λ•Œλ¬Έμ— μ•ˆμ‹¬ν•˜κ³  κ³΅μœ ν•  수 μžˆλ‹€. λ”°λΌμ„œ λΆˆλ³€ 클래슀라면 ν•œλ²ˆ λ§Œλ“  μΈμŠ€ν„΄μŠ€λ₯Ό μ΅œλŒ€ν•œ μž¬ν™œμš©ν•˜κΈ°λ₯Ό κΆŒν•œλ‹€.

λΆˆλ³€ ν΄λž˜μŠ€λŠ” 자주 μ‚¬μš©λ˜λŠ” μΈμŠ€ν„΄μŠ€λ₯Ό μΊμ‹±ν•˜μ—¬ 같은 μΈμŠ€ν„΄μŠ€λ₯Ό 쀑볡 μƒμ„±ν•˜μ§€ μ•Šκ²Œ ν•΄μ£ΌλŠ” 정적 νŒ©ν„°λ¦¬λ₯Ό μ œκ³΅ν•  수 μžˆλ‹€. μƒˆλ‘œμš΄ 클래슀λ₯Ό 섀계할 λ•Œ public μƒμ„±μž λŒ€μ‹  정적 νŒ©ν„°λ¦¬λ₯Ό λ§Œλ“€μ–΄λ‘λ©΄, ν΄λΌμ΄μ–ΈνŠΈλ₯Ό μˆ˜μ •ν•˜μ§€ μ•Šκ³ λ„ ν•„μš”μ— 따라 μΊμ‹œ κΈ°λŠ₯을 λ‚˜μ€‘μ— 덧뢙일 수 μžˆλ‹€.

BigInteger answer = BigInteger.valueOf(42L);

λΆˆλ³€ κ°μ²΄λŠ” 자유둭게 κ³΅μœ ν•  수 μžˆμŒμ€ λ¬Όλ‘ , λΆˆλ³€ κ°μ²΄λΌλ¦¬λŠ” λ‚΄λΆ€ 데이터λ₯Ό κ³΅μœ ν•  수 μžˆλ‹€. 객체λ₯Ό λ§Œλ“€ λ•Œ λ‹€λ₯Έ λΆˆλ³€ 객체듀을 κ΅¬μ„±μš”μ†Œλ‘œ μ‚¬μš©ν•˜λ©΄ 이점이 λ§Žλ‹€. 쒋은 예둜, λΆˆλ³€ κ°μ²΄λŠ” 맡의 킀와 집합(Set)의 μ›μ†Œλ‘œ 쓰기에 μ•ˆμ„±λ§žμΆ€μ΄λ‹€. λ§΅μ΄λ‚˜ 집합은 μ•ˆμ— λ‹΄κΈ΄ 값이 λ°”λ€Œλ©΄ λΆˆλ³€μ‹μ΄ ν—ˆλ¬Όμ–΄μ§€λŠ”λ°, λΆˆλ³€ 객체λ₯Ό μ‚¬μš©ν•˜λ©΄ 그런 걱정은 ν•˜μ§€ μ•Šμ•„λ„ λœλ‹€.

λΆˆλ³€ ν΄λž˜μŠ€μ—λ„ 단점은 μžˆλ‹€.

값이 λ‹€λ₯΄λ©΄ λ°˜λ“œμ‹œ λ…λ¦½λœ 객체둜 λ§Œλ“€μ–΄μ•Ό ν•œλ‹€λŠ” 것이닀. κ°’μ˜ κ°€μ§“μˆ˜κ°€ λ§Žλ‹€λ©΄ 이듀을 λͺ¨λ‘ λ§Œλ“œλŠ” 데 큰 λΉ„μš©μ„ μΉ˜μ›Œμ•Ό ν•œλ‹€.

    BigInteger moby = ...;
    moby = moby.flipBit(0);

이 λ¬Έμ œμ— λŒ€μ²˜ν•˜λŠ” 방법은 두 가지닀.

첫 λ²ˆμ§ΈλŠ” ν”νžˆ 쓰일 닀단계 μ—°μ‚° 듀을 μ˜ˆμΈ‘ν•˜μ—¬ κΈ°λ³Έ κΈ°λŠ₯으둜 μ œκ³΅ν•˜λŠ” 방법이닀. μ΄λŸ¬ν•œ 닀단계 연산을 기본으둜 μ œκ³΅ν•œλ‹€λ©΄ 더 이상 각 λ‹¨κ³„λ§ˆλ‹€ 객체λ₯Ό μƒμ„±ν•˜μ§€ μ•Šμ•„λ„ λœλ‹€. ν΄λΌμ΄μ–ΈνŠΈλ“€μ΄ μ›ν•˜λŠ” λ³΅μž‘ν•œ μ—°μ‚° 듀을 μ •ν™•νžˆ μ˜ˆμΈ‘ν•  수 μžˆλ‹€λ©΄ package-private의 κ°€λ³€ λ™λ°˜ 클래슀만으둜 μΆ©λΆ„ν•˜λ‹€. μžλ°” ν”Œλž«νΌ λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œ 이에 ν•΄λ‹Ήν•˜λŠ” λŒ€ν‘œμ μΈ μ˜ˆκ°€ λ°”λ‘œ String ν΄λž˜μŠ€λ‹€. κ·Έλ ‡λ‹€λ©΄ String의 κ°€λ³€ λ™λ°˜ ν΄λž˜μŠ€λŠ” λ°”λ‘œ StringBuilder이닀.

κ°€λ³€ λ™λ°˜ 클래슀의 λ™μž‘μ›λ¦¬λŠ”?

ν΄λž˜μŠ€κ°€ λΆˆλ³€μž„μ„ 보μž₯ν•˜λ €λ©΄ μžμ‹ μ„ μƒμ†ν•˜μ§€ λͺ»ν•˜κ²Œ final 클래슀둜 μ„ μ–Έν•˜λŠ” κ²ƒμ΄μ§€λ§Œ 더 μœ μ—°ν•œ 방법이 μžˆλ‹€. λͺ¨λ“  μƒμ„±μžλ₯Ό private ν˜Ήμ€ package-private으둜 λ§Œλ“€κ³  public 정적 νŒ©ν„°λ¦¬λ₯Ό μ œκ³΅ν•˜λŠ” 방법이닀.

    public class Complex {
    	private final double re;
    	private final double im;
    
    	private Complex(double re, double im) {
    		this.re = re;
    		this.im = im;
    	}
    	public static Complex valueOf(double re, double im) {
    		return new Complex(re,im);
    	}
    	...
    }

νŒ¨ν‚€μ§€ λ°”κΉ₯의 ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ 바라본 이 λΆˆλ³€ κ°μ²΄λŠ” 사싀상 final이닀. public μ΄λ‚˜ protected μƒμ„±μžκ°€ μ—†μœΌλ‹ˆ λ‹€λ₯Έ νŒ¨ν‚€μ§€μ—μ„œλŠ” 이 클래슀λ₯Ό ν™•μž₯ν•˜λŠ” 게 λΆˆκ°€λŠ₯ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.

κ²Œν„°(getter)κ°€ μžˆλ‹€κ³  ν•΄μ„œ 무쑰건 μ„Έν„°(setter)λ₯Ό λ§Œλ“€μ§€λŠ” 말자. ν΄λž˜μŠ€λŠ” κΌ­ ν•„μš”ν•œ κ²½μš°κ°€ μ•„λ‹ˆλΌλ©΄ λΆˆλ³€μ΄μ–΄μ•Ό ν•œλ‹€.

PhoneNumber와 Complex 같은 λ‹¨μˆœν•œ κ°’ κ°μ²΄λŠ” 항상 λΆˆλ³€μœΌλ‘œ λ§Œλ“€μž. λΆˆλ³€μœΌλ‘œ λ§Œλ“€ 수 μ—†λŠ” ν΄λž˜μŠ€λΌλ„ λ³€κ²½ν•  수 μžˆλŠ” 뢀뢄을 μ΅œμ†Œν™˜μœΌλ‘œ μ€„μ΄μž. 객체가 κ°€μ§ˆ 수 μžˆλŠ” μƒνƒœμ˜ 수λ₯Ό 쀄이면 κ·Έ 객체λ₯Ό μ˜ˆμΈ‘ν•˜κΈ° 쉬어지고 였λ₯˜κ°€ 생길 κ°€λŠ₯성이 쀄어든닀.

java.util.concurrent νŒ¨ν‚€μ§€μ˜ CountDownLatch ν΄λž˜μŠ€κ°€ μ΄μƒμ˜ 원칙을 잘 λ°˜μ¦ν•œλ‹€. 비둝 κ°€λ³€ ν΄λž˜μŠ€μ§€λ§Œ κ°€μ§ˆ 수 μžˆλŠ” μƒνƒœμ˜ μˆ˜κ°€ λ§Žμ§€ μ•Šλ‹€.

CountDownLatch κ΅¬μ‘°λŠ” μ–΄λ–»κ²Œ λ˜μ–΄ μžˆλ‚˜?