Home [Effective Java] Item 1
Post
Cancel

[Effective Java] Item 1

Effective Java - Item 1

❓ 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œ(Static Factory Method)λž€?

였직 클래슀의 μΈμŠ€ν„΄μŠ€λ§Œμ„ λ°˜ν™˜ν•˜κΈ° μœ„ν•΄ μ •μ˜λœ 정적 λ©”μ†Œλ“œλ₯Ό 정적 νŒ©ν† λ¦¬ λ©”μ†Œλ“œλΌκ³  ν•œλ‹€.

  • μ½”λ“œ

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
      public final class LocalTime
      			implements Temporal, TemporalAdjuster, Comparable<LocalTime>, Serializable {
        	
      	...
      		public static LocalTime of(int hour, int minute, int second) {
      		        HOUR_OF_DAY.checkValidValue(hour);
      		        if ((minute | second) == 0) {
      		            return HOURS[hour];  // for performance
      		        }
      		        MINUTE_OF_HOUR.checkValidValue(minute);
      		        SECOND_OF_MINUTE.checkValidValue(second);
      		        return new LocalTime(hour, minute, second, 0);
      		}
        
      	...
      		private LocalTime(int hour, int minute, int second, int nanoOfSecond) {
      		        this.hour = (byte) hour;
      		        this.minute = (byte) minute;
      		        this.second = (byte) second;
      		        this.nano = nanoOfSecond;
      		}
      	...
      }
    

κ·Έλ ‡λ‹€λ©΄ μ™œ μƒμ„±μžλ₯Ό ν˜ΈμΆœν•˜μ§€ μ•Šκ³  정적 νŒ©ν† λ¦¬ λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ”μ§€, 정적 νŒ©ν† λ¦¬ λ©”μ†Œλ“œμ˜ μž₯/단점을 μ •λ¦¬ν•΄λ³΄μž.

μž₯점

첫 번째, 이름을 κ°€μ§ˆ 수 μžˆλ‹€.

객체λ₯Ό μƒμ„±μžλ‘œ ν˜ΈμΆœν•  λ•Œμ—λŠ” 클래슀의 λ§€κ°œλ³€μˆ˜κ°€ λ§Žμ„ 수둝, 같은 νƒ€μž…μ˜ λ§€κ°œλ³€μˆ˜κ°€ μ—¬λŸ¬ 개 μ‘΄μž¬ν• μˆ˜λ‘, κ°œλ°œμžλ“€μ€ 각 μƒμ„±μžλ“€μ΄ μ–΄λ–€ μ˜λ―ΈμΈμ§€ μ‰½κ²Œ νŒŒμ•…ν•  수 μ—†λ‹€. λ˜ν•œ, public μƒμ„±μžλŠ” ν•˜λ‚˜μ˜ μ‹œκ·Έλ‹ˆμ²˜λ‘œ ν•˜λ‚˜λ§Œ 생성할 수 μžˆλ‹€. 예λ₯Ό λ“€μ–΄, 학ꡐλ₯Ό μ˜λ―Έν•˜λŠ” ν΄λž˜μŠ€μ— 학생과 μ„ μƒλ‹˜μ΄ μ‘΄μž¬ν•œλ‹€. μ΄λ•Œ ν•™μƒμ˜ 이름인 String λ³€μˆ˜λ₯Ό λ°›λŠ” μƒμ„±μžκ°€ μ‘΄μž¬ν•œλ‹€λ©΄ μ„ μƒλ‹˜μ˜ 이름인 String λ³€μˆ˜λ₯Ό λ°›λŠ” μƒμ„±μžλŠ” 였λ₯˜κ°€ λ°œμƒν•œλ‹€. 이미 ν•˜λ‚˜μ˜ String λ³€μˆ˜λ₯Ό λ°›λŠ” μƒμ„±μžκ°€ μ‘΄μž¬ν•˜κΈ° λ•Œλ¬Έμ— λ‹€λ₯Έ μƒμ„±μžκ°€ 호좜될 수 있기 λ•Œλ¬Έμ΄λ‹€. 반면 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œμ—μ„œλŠ” λ©”μ„œλ“œλͺ…을 지정할 수 있기 λ•Œλ¬Έμ— ν•œ ν΄λž˜μŠ€μ— μ‹œκ·Έλ‹ˆμ²˜κ°€ 같은 μƒμ„±μžκ°€ μ—¬λŸ¬ 개 μ‘΄μž¬ν•˜λŠ” κ²½μš°μ—λŠ” μƒμ„±μžλ₯Ό 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œλ‘œ λ°”κΎΈκ³  λ©”μ†Œλ“œλͺ…μœΌλ‘œ 각각의 νŠΉμ„±μ„ λ‚˜νƒ€λ‚΄μ–΄ μ‚¬μš©ν•  수 μžˆλ‹€.

  • μ½”λ“œ

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
      public class School {
      	String studentName;
      	String teacherName;
      	int grade;
        
      	public School(String studentName) {
      		this.studentName = studentName;
      	}
        
      // μ—λŸ¬
      	public School(String teacherName) { 
      		this.teacherName= teacherName;
      	}
        
      	public static School createStudent(String name, int grade) {
      		return new School(name, grede);
      	}
        
      	public static School createTeacher(String name, int grade) {
      		return new School(name, grede);
      	}
        
        public static void main(String[] args) {
      		School student = createStudent("학생", 3);
      		School teacher = createTeacher("μ„ μƒλ‹˜", 1);
      	}
      }
    

    β†’ λ§€κ°œλ³€μˆ˜μ˜ μ’…λ₯˜μ™€ κ°œμˆ˜κ°€ κ°™μ§€λ§Œ λ©”μ†Œλ“œλͺ…μœΌλ‘œ 인해 λ°˜ν™˜λ˜λŠ” μΈμŠ€ν„΄μŠ€μ˜ λͺ…ν™•ν•œ ꡬ뢄이 κ°€λŠ₯ν•˜λ‹€.

두 번째, 호좜될 λ•Œλ§ˆλ‹€ μΈμŠ€ν„΄μŠ€λ₯Ό μƒˆλ‘œ μƒμ„±ν•˜μ§€λŠ” μ•Šμ•„λ„ λœλ‹€.

주둜 μ‚¬μš©λ˜λŠ” λΆˆλ³€ 객체가 μ‘΄μž¬ν•œλ‹€λ©΄ 미리 μƒμ„±λœ μΈμŠ€ν„΄μŠ€λ₯Ό μΊμ‹±ν•˜μ—¬ μž¬ν™œμš©ν•¨μœΌλ‘œμ¨ λΆˆν•„μš”ν•˜κ²Œ 객체λ₯Ό 생성할 ν•„μš”κ°€ μ—†λ‹€. λŒ€ν‘œμ μœΌλ‘œ Boolean.valueOf(boolean) λ©”μ†Œλ“œκ°€ μžˆλ‹€. Boolean ν΄λž˜μŠ€μ—μ„œλŠ” TURE, FALSEλ₯Ό μƒμˆ˜λ‘œ μ •μ˜ν•΄ 놓고 valueOf() λ©”μ†Œλ“œκ°€ 호좜 λ˜μ—ˆμ„ λ•Œ 객체λ₯Ό μƒˆλ‘œ μƒμ„±ν•˜μ§€ μ•Šκ³  μ‘΄μž¬ν•˜λŠ” μƒμˆ˜λ₯Ό λ°˜ν™˜ν•΄μ€€λ‹€.

  • μ½”λ“œ

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
      public final class Boolean implements java.io.Serializable,
                                            Comparable<Boolean>
      {
          public static final Boolean TRUE = new Boolean(true);
          public static final Boolean FALSE = new Boolean(false);
      	...
      		public static Boolean valueOf(boolean b) {
              return (b ? TRUE : FALSE);
          }
      	...
      }
    

    β†’ valueOf(b) λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ 이미 μƒμ„±λ˜μ–΄ μžˆλŠ” 객체λ₯Ό λ°˜ν™˜ν•œλ‹€.

μ„Έ 번째, λ°˜ν™˜ νƒ€μž…μ˜ ν•˜μœ„ νƒ€μž… 객체λ₯Ό λ°˜ν™˜ν•  수 μžˆλŠ” λŠ₯λ ₯이 μžˆλ‹€.

ν•˜μœ„ ν΄λž˜μŠ€λ“€μ΄ ν•˜λ‚˜μ˜ μƒμœ„ 클래슀λ₯Ό 상속 λ°›λŠ” ꡬ쑰인 κ²½μš°μ— μƒμœ„ ν΄λž˜μŠ€μ—μ„œλŠ” μ–΄λ– ν•œ 쑰건에 따라 ν•˜μœ„ 클래슀 객체듀을 λ°˜ν™˜ν•  수 μžˆλ‹€. μ΄λ•Œ, ν•˜μœ„ 클래슀의 κ΅¬ν˜„μ²΄λ₯Ό κ³΅κ°œν•˜μ§€ μ•Šκ³ λ„ λ°˜ν™˜μ΄ κ°€λŠ₯ν•˜κΈ° λ•Œλ¬Έμ— APIλ₯Ό μž‘κ²Œ μœ μ§€ν•  수 μžˆλ‹€. λŒ€ν‘œμ μœΌλ‘œ, java.util.Collections ν΄λž˜μŠ€μ—μ„œλŠ” μˆ˜μ • λΆˆκ°€λ‚˜ 동기화 λ“±μ˜ κΈ°λŠ₯을 ν¬ν•¨ν•˜μ—¬ 총 45개의 μœ ν‹Έλ¦¬ν‹° κ΅¬ν˜„μ²΄λ₯Ό μ œκ³΅ν•˜λŠ”λ° λŒ€λΆ€λΆ„ 정적 νŒ©ν† λ¦¬ λ©”μ†Œλ“œλ₯Ό ν†΅ν•˜μ—¬ 얻을 수 μžˆλ‹€.

  • μ½”λ“œ

    1
    2
    3
    4
    5
    6
    7
    
      public class Arrays {
      	...
      		public static <T> List<T> asList(T... a) {
              return new ArrayList<>(a);
          }
      	...
      }
    

    β†’ java.util.Arrays ν΄λž˜μŠ€μ—μ„œ asList() λ©”μ†Œλ“œλ₯Ό 톡해 List의 ν•˜μœ„ 클래슀인 ArrayListλ₯Ό λ°˜ν™˜ν•œλ‹€.

λ„€ 번째, μž…λ ₯ λ§€κ°œλ³€μˆ˜μ— 따라 맀번 λ‹€λ₯Έ 클래슀의 객체λ₯Ό λ°˜ν™˜ν•  수 μžˆλ‹€.

λ‹¨μˆœνžˆ ν•˜μœ„ ν΄λž˜μŠ€λ§Œμ„ λ°˜ν™˜ν•˜λŠ” 것이 μ•„λ‹ˆλΌ λ§€κ°œλ³€μˆ˜μ— λ”°λΌμ„œ 각각 λ‹€λ₯Έ ν•˜μœ„ 클래슀의 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” 것이 κ°€λŠ₯ν•˜λ‹€. μ΄λ•Œ, ν΄λΌμ΄μ–ΈνŠΈλŠ” μ–΄λ–€ 객체가 λ°˜ν™˜ λ˜λŠ” 지에 λŒ€ν•΄μ„œλŠ” μ•Œ ν•„μš”κ°€ μ—†λ‹€. 예λ₯Ό λ“€μ–΄ EnumSet 클래슀의 noneOf()λ©”μ†Œλ“œλŠ” universe 값에 λ”°λΌμ„œ λ‹€λ₯Έ ν•˜μœ„ 클래슀λ₯Ό λ°˜ν™˜ν•΄μ€€λ‹€.

  • μ½”λ“œ

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
      public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
          implements Cloneable, java.io.Serializable
      {
      		public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
              Enum<?>[] universe = getUniverse(elementType);
              if (universe == null)
                  throw new ClassCastException(elementType + " not an enum");
        
              if (universe.length <= 64)
                  return new RegularEnumSet<>(elementType, universe);
              else
                  return new JumboEnumSet<>(elementType, universe);
          }
      }
    

    β†’ EnumSet 클래슀의 noneOf() λ©”μ†Œλ“œλŠ” universe의 length 값이 64개 μ΄ν•˜μΌ 경우 RegularEnumSet, 아닐 κ²½μš°μ—λŠ” JumboEnumSet 객체λ₯Ό λ°˜ν™˜ν•΄μ€€λ‹€.

λ‹€μ„― 번째, 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œλ₯Ό μž‘μ„±ν•˜λŠ” μ‹œμ μ—λŠ” λ°˜ν™˜ν•  객체의 ν΄λž˜μŠ€λŠ” μ‘΄μž¬ν•˜μ§€ μ•Šμ•„λ„ λœλ‹€.

μ§€κΈˆκΉŒμ§€λŠ” 이미 κ΅¬ν˜„λ˜μ–΄ μžˆλŠ” κ΅¬ν˜„μ²΄κ°€ 기쀀이 λ˜μ—ˆμ§€λ§Œ, 정적 νŒ©ν† λ¦¬ λ©”μ†Œλ“œλ₯Ό ν™œμš©ν–ˆμ„ λ•Œμ— κ΅¬ν˜„λ˜μ–΄μžˆμ§€ μ•Šμ€ 객체의 ν΄λž˜μŠ€κ°€ μ‘΄μž¬ν•˜μ§€ μ•Šμ•„λ„ λœλ‹€. μ΄λŸ¬ν•œ νŠΉμ§•μ€ μ„œλΉ„μŠ€ 제곡자 ν”„λ ˆμž„μ›Œν¬(Service Provider Framework) 의 근간이 λœλ‹€. μ„œλΉ„μŠ€λ₯Ό μ œκ³΅ν•˜λŠ” μ œκ³΅μžλŠ” μ„œλΉ„μŠ€μ˜ κ΅¬ν˜„μ²΄μ΄κ³ , 이 κ΅¬ν˜„μ²΄λ“€μ„ ν΄λΌμ΄μ–ΈνŠΈμ— μ œκ³΅ν•˜λŠ” 역할을 ν”„λ ˆμž„μ›Œν¬κ°€ ν†΅μ œν•˜μ—¬ ν΄λΌμ΄μ–ΈνŠΈλ₯Ό κ΅¬ν˜„μ²΄λ‘œλΆ€ν„° 뢄리해쀀닀. μ„œλΉ„μŠ€ 제곡자 ν”„λ ˆμž„μ›Œν¬λŠ” 3개의 핡심 μ»΄ν¬λ„ŒνŠΈλ‘œ 이루어져 μžˆλ‹€.

  • μ„œλΉ„μŠ€ μΈν„°νŽ˜μ΄μŠ€ (service interface) : κ΅¬ν˜„μ²΄μ˜ λ™μž‘μ„ μ •μ˜ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€
  • 제곡자 등둝 API (provider registration API) : μ œκ³΅μžκ°€ κ΅¬ν˜„μ²΄λ₯Ό λ“±λ‘ν•˜λŠ” API
  • μ„œλΉ„μŠ€ μ ‘κ·Ό API (service access API) : ν΄λΌμ΄μ–ΈνŠΈκ°€ μ„œλΉ„μŠ€μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό 얻을 λ•Œ μ‚¬μš©ν•˜λŠ” API

이 밖에 μ’…μ’… λ„€ 번째 μ»΄ν¬λ„ŒνŠΈμΈ μ„œλΉ„μŠ€ 제곡자 μΈν„°νŽ˜μ΄μŠ€ (service provider interface) κ°€ 쓰인닀.

ν•΄λ‹Ή μΈν„°νŽ˜μ΄μŠ€κ°€ μ—†λ‹€λ©΄ 각 κ΅¬ν˜„μ²΄λ₯Ό μΈμŠ€ν„΄μŠ€λ‘œ λ§Œλ“€ λ•Œ λ¦¬ν”Œλ ‰μ…˜μ„ μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.

λŒ€ν‘œμ μΈ μ„œλΉ„μŠ€ 제곡자 ν”„λ ˆμž„μ›Œν¬λ‘œλŠ” JDBC(Java Database Connectivity)κ°€ μ‘΄μž¬ν•œλ‹€.

  • JDBC : javaμ—μ„œ λ°μ΄ν„°λ² μ΄μŠ€μ— 접속할 수 μžˆλ„λ‘ ν•˜λŠ” java API

    β€” Connection : μ„œλΉ„μŠ€ μΈν„°νŽ˜μ΄μŠ€

    β€” DriverManager.registerDriver : 제곡자 등둝 API

    β€” DriverManager.getConnection : μ„œλΉ„μŠ€ 등둝 API

    β€” Driver : μ„œλΉ„μŠ€ 제곡자 μΈν„°νŽ˜μ΄μŠ€

단점

첫 번째, 상속을 ν•˜λ €λ©΄ publicμ΄λ‚˜ protected μƒμ„±μžκ°€ ν•„μš”ν•˜λ‹ˆ 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œλ§Œ μ œκ³΅ν•˜λ©΄ ν•˜μœ„ 클래슀λ₯Ό λ§Œλ“€ 수 μ—†λ‹€.

예λ₯Ό λ“€μ–΄ java.util.Collections 클래슀의 κ²½μš°μ—λŠ” λͺ¨λ“  μƒμ„±μžκ°€ private둜 μ„ μ–Έλ˜μ–΄ 있기 λ•Œλ¬Έμ— java.util.Collections둜 λ§Œλ“  κ΅¬ν˜„μ²΄λŠ” 상속이 λΆˆκ°€λŠ₯ν•˜λ‹€. λ‹€λ§Œ μ΄λŸ¬ν•œ 점은 상속보닀 μ»΄ν¬μ§€μ…˜μ„ μ‚¬μš©ν•˜λ„λ‘ μœ λ„ν•˜κ³  λΆˆλ³€ νƒ€μž…μœΌλ‘œ λ§Œλ“€κΈ° μœ„ν•΄ μ œμ•½μ„ μ§€μΌœμ•Ό ν•œλ‹€λŠ” μ μ—μ„œ 였히렀 μž₯점이 될 수 μžˆλ‹€.

두 번째, 정적 νŒ©ν† λ¦¬ λ©”μ†Œλ“œλŠ” ν”„λ‘œκ·Έλž˜λ¨Έκ°€ μ°ΎκΈ° μ–΄λ ΅λ‹€.

public μƒμ„±μžλŠ” API μ„€λͺ…μ—μ„œ 확인할 수 있기 λ•Œλ¬Έμ— ν”„λ‘œκ·Έλž˜λ¨Έλ“€μ΄ μ•ŒκΈ° μ‰½μ§€λ§Œ, 정적 νŒ©ν† λ¦¬ λ©”μ†Œλ“œκ°™μ€ κ²½μš°μ—λŠ” javadocμ—μ„œλ„ λ”°λ‘œ μ •λ¦¬ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— API λ¬Έμ„œλ₯Ό 잘 μž‘μ„±ν•˜κ³  λ©”μ†Œλ“œλͺ…을 μ•Œλ €μ§„ κ·œμ•½μ— 따라 지어 ν”„λ‘œκ·Έλž˜λ¨Έκ°€ μ•ŒκΈ° μ‰½κ²Œ ν•΄μ£Όμ–΄μ•Ό ν•œλ‹€.

  • from : λ§€κ°œλ³€μˆ˜λ₯Ό ν•˜λ‚˜λ₯Ό λ°›μ•„ ν•΄λ‹Ή νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•˜λŠ” ν˜•λ³€ν™˜ λ©”μ„œλ“œ

    β†’ Date d = Date.from(instant);

  • of : μ—¬λŸ¬ λ§€κ°œλ³€μˆ˜λ₯Ό λ°›μ•„ μ ν•©ν•œ νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•˜λŠ” 집계 λ©”μ„œλ“œ

    β†’ Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);

  • valueOf : fromκ³Ό of의 더 μžμ„Έν•œ 버전

    β†’ BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);

  • instance / getInstance : (λ§€κ°œλ³€μˆ˜λ₯Ό λ°›λŠ”λ‹€λ©΄) λ§€κ°œλ³€μˆ˜λ‘œ λͺ…μ‹œν•œ μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•˜μ§€λ§Œ, 같은 μΈμŠ€ν„΄μŠ€μž„μ„ 보μž₯ν•˜μ§€λŠ” μ•ŠλŠ”λ‹€.

    β†’ StackWalker luke = StackWalker.getInstance(options);

  • create / newInstance : instance ν˜Ήμ€ getInstance와 κ°™μ§€λ§Œ, 맀번 μƒˆλ‘œμš΄ μΈμŠ€ν„΄μŠ€λ₯Ό 생성해 λ°˜ν™˜ν•¨μ„ 보μž₯ν•œλ‹€.

    β†’ Object newArray = Array.newInstance(classObject, arrayLen);

  • getType : getInstance와 κ°™μœΌλ‚˜, 생성할 ν΄λž˜μŠ€κ°€ μ•„λ‹Œ λ‹€λ₯Έ ν΄λž˜μŠ€μ— νŒ©ν† λ¦¬ λ©”μ„œλ“œλ₯Ό μ •μ˜ν•  λ•Œ μ“΄λ‹€. β€œType”은 νŒ©ν† λ¦¬ λ©”μ†Œλ“œκ°€ λ°˜ν™˜ν•  객체의 νƒ€μž…μ΄λ‹€.

    β†’ FileStore fs = Files.getFileStore(path);

  • newType : newInstance와 κ°™μœΌλ‚˜ 생성할 ν΄λž˜μŠ€κ°€ μ•„λ‹Œ λ‹€λ₯Έ ν΄λž˜μŠ€μ— νŒ©ν† λ¦¬ λ©”μ„œλ“œλ₯Ό μ •μ˜ν•  λ•Œ μ“΄λ‹€. β€œType”은 νŒ©ν† λ¦¬ λ©”μ†Œλ“œκ°€ λ°˜ν™˜ν•  객체의 νƒ€μž…μ΄λ‹€.

    β†’ BufferedReader br = Files.newBufferedReader(path);

  • type : getTypeκ³Ό newType의 κ°„κ²°ν•œ 버전

    β†’ List<Complaint> litany = Collections.list(legacyLitany);

This post is licensed under CC BY 4.0 by the author.

[Java] Comparable κ³Ό Comparator

[Effective Java] Item 2