[μ΄νŽ™ν‹°λΈŒ μžλ°”] Item29. 이왕이면 μ œλ„€λ¦­ νƒ€μž…μœΌλ‘œ λ§Œλ“€λΌ.

2023. 3. 20. 10:16ㆍJAVA/Effective JAVA

728x90

 

[μ΄νŽ™ν‹°λΈŒ μžλ°”] Item29. 이왕이면 μ œλ„€λ¦­ νƒ€μž…μœΌλ‘œ λ§Œλ“€λΌ. 

 

public class Stack
{
   private Object[] elements;
   private int size = 0;
   private static final int DEFAULT_INITIAL_CAPACITY = 16;
   
   public Stack()
   {
      elements = new Object[DEFAULT_INITIAL_CAPACITY];
   }
   
   public void push(Object e)
   {
      ensureCapacity();
   }
   
   public Object pop()
   {
      if (size == 0) {
         throw new EmptyStackException();
      }
      
      Object result = elements[--size];
      elements[size] = null;
      return result;
   }
   
   public boolean isEmpty()
   {
      return size == 0;
   }
   
   private void ensureCapacity()
   {
      if (elements.length == size) {
         elements = Arrays.copyOf(elements, 2 * size + 1);
      }
   }
   
   public static void main(String[] args)
   {
      Stack stack = new Stack();
      for (String arg: List.of("a", "b", "c"))
      {
         stack.push(arg);
      }
      while (!stack.isEmpty())
      {
         System.out.println(((String) stack.pop()).toUpperCase());
      }
   }
}

이 ν΄λž˜μŠ€μ—μ„œλŠ” Object 배열을 μ‚¬μš©ν•΄μ„œ Stack을 κ΅¬ν˜„ν–ˆλŠ”λ° μ§€κΈˆ ν΄λž˜μŠ€μ—μ„œλŠ” ν΄λΌμ΄μ–ΈνŠΈ μ½”λ“œμ—μ„œ κΊΌλ‚Ό λ•Œ λ§ˆλ‹€ 객체λ₯Ό ν˜•λ³€ν™˜ ν•΄μ•Ό ν•˜λŠ”λ° μ΄λ•Œ λŸ°νƒ€μž„ 였λ₯˜κ°€ λ‚  μœ„ν—˜μ΄ μžˆλ‹€. 

 

λ”°λΌμ„œ 이 ν΄λž˜μŠ€λŠ” μ›λž˜ μ œλ„€λ¦­ νƒ€μž…μ΄μ–΄μ•Ό ν•œλ‹€. 

1️⃣  E[] λ₯Ό μ΄μš©ν•œ μ œλ„€λ¦­ μŠ€νƒ 

public class Stack<E>
{
   private E[] elements;
   private int size = 0;
   private static final int DEFAULT_INITIAL_CAPACTIY = 16;
   
   // 배열을 μ‚¬μš©ν•œ μ½”λ“œλ₯Ό μ œλ„€λ¦­μœΌλ‘œ λ§Œλ“œλŠ” 방법 1
   // λ°°μ—΄ elementsλŠ” push(E) 둜 λ„˜μ–΄μ˜¨ E μΈμŠ€ν„΄μŠ€λ§Œ λ‹΄λŠ”λ‹€.
   // λ”°λΌμ„œ νƒ€μž… μ•ˆμ •μ„±μ„ 보μž₯ν•˜μ§€λ§Œ,
   // 이 λ°°μ—΄μ˜ λŸ°νƒ€μž„ νƒ€μž…μ€ E[]κ°€ μ•„λ‹Œ Object[] λ‹€!
   // -> 이 λ°©λ²•μ˜ μœ μΌν•œ 단점은 Heap μ˜€μ—Όμ΄ λ°œμƒν•  수 μžˆλ‹€λŠ” 점이닀.
   @SuppressWarnings("unchecked")
   public Stack()
   {
      elements = (E[]) new Object[DEFAULT_INITIAL_CAPACTIY];
   }
   
   public void push(E e)
   {
      ensureCapacity();
      elements[size++] = e;
   }
   
   public E pop()
   {
      if (size == 0) {
         throw new EmptyStackException();
      }
      
      E result = elements[--size];
      elements[size] = null;
      return result;
   }
   
   public boolean isEmpty()
   {
      return size == 0;
   }
   
   
   private void ensureCapacity()
   {
      if (elements.length == 0) {
         elements = Arrays.copyOf(elements, 2 * size + 1);
      }
   }
   
   public static void main(String[] args)
   {
      Stack<String> stack = new Stack<>();
      for (String arg : List.of("a", "b", "c"))
      {
         stack.push(arg);
      }
      while (stack.isEmpty())
      {
         System.out.println(stack.pop().toUpperCase());
      }
   }
}

일반 클래슀λ₯Ό μ œλ„€λ¦­ 클래슀둜 λ§Œλ“œλŠ” 첫번째 방법은 클래슀 선언에 νƒ€μž… λ§€κ°œλ³€μˆ˜λ₯Ό μΆ”κ°€ν•˜λŠ” 일이닀. 

그리고 μ΄λ•Œ νƒ€μž… μ΄λ¦„μœΌλ‘œλŠ” 보톡 Eλ₯Ό 많이 μ‚¬μš©ν•œλ‹€. 

@SuppressWarnings("unchecked")
public Stack()
{
   elements = (E[]) new Object[DEFAULT_INITIAL_CAPACTIY];
}

μ—¬κΈ°μ„œ 보면 E와 같은 싀체화 λΆˆκ°€ νƒ€μž…μœΌλ‘œλŠ” 배열을 λ§Œλ“€ 수 μ—†κΈ° λ•Œλ¬Έμ— Object 배열을 μƒμ„±ν•œ λ‹€μŒμ— μ œλ„€λ¦­ λ°°μ—΄λ‘œ ν˜•λ³€ν™˜μ„ ν•˜λŠ” 방법이닀. 그러고 λ‚˜λ©΄ 이제 컴파일 였λ₯˜κ°€ λ°œμƒν•˜μ§€λŠ” μ•Šμ§€λ§Œ νƒ€μž… μ•ˆμ „ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— κ²½κ³ κ°€ λœ¬λ‹€!  

 

컴파일러 μž…μž₯μ—μ„œ 보면 이 ν”„λ‘œκ·Έλž¨μ΄ νƒ€μž… μ•ˆμ „ν•œμ§€ 증λͺ…ν•  방법이 μ—†μ§€λ§Œ μš°λ¦¬λŠ” μ•Œ 수 μžˆλ‹€. 

elements 배열은 private ν•„λ“œμ— μ €μž₯되고, ν΄λΌμ΄μ–ΈνŠΈλ‘œ λ°˜ν™˜λ˜κ±°λ‚˜ λ‹€λ₯Έ λ©”μ„œλ“œμ— μ „λ‹¬λ˜λŠ” 일이 μ—†λ‹€. 

그리고 push λ©”μ„œλ“œλ₯Ό 톡해 배열에 μ €μž₯λ˜λŠ” μ›μ†Œμ˜ νƒ€μž…μ€ 항상 E이닀. λ”°λΌμ„œ 이 비검사 ν˜•λ³€ν™˜μ€ ν™•μ‹€νžˆ μ•ˆμ „ν•˜λ‹€! 

 

μ΄λ ‡κ²Œ 비검사 ν˜•λ³€ν™˜μ΄ μ•ˆμ „ν•˜λ‹€λΌλŠ” 것이 증λͺ…λœλ‹€λ©΄ λ²”μœ„λ₯Ό μ΅œμ†Œλ‘œ μ’ν˜€μ„œ @SuppressWarnings("unchecked") μ–΄λ…Έν…Œμ΄μ…˜μ„ ν†΅ν•΄μ„œ κ²½κ³ λ₯Ό 숨길 수 μžˆλ‹€. 

 

 

2️⃣ Object[] λ₯Ό μ΄μš©ν•œ μ œλ„€λ¦­ Stack 

public class Stack<E>
{
   private Object[] elements;
   private int size = 0;
   private static final int DEFAULT_INITIAL_CAPACTIY = 16;
   
   public Stack()
   {
      elements = new Object[DEFAULT_INITIAL_CAPACTIY];
   }
   
   public void push(E e)
   {
      ensureCapacity();
      elements[size++] = e;
   }
   
   // 배열을 μ‚¬μš©ν•œ μ½”λ“œλ₯Ό μ œλ„€λ¦­μœΌλ‘œ λ§Œλ“œλŠ” 방법 2
   // 비검사 κ²½κ³ λ₯Ό 적절히 μˆ¨κΈ΄λ‹€.
   public E pop()
   {
      if (size == 0) {
         throw new EmptyStackException();
      }

      // pushμ—μ„œ E νƒ€μž…λ§Œ ν—ˆμš©ν•˜λ―€λ‘œ 이 ν˜•λ³€ν™˜μ€ μ•ˆμ „ν•˜λ‹€.
      @SuppressWarnings("unchecked")
      E result = (E) elements[--size];
      elements[size] = null; // λ‹€ μ“΄ μ°Έμ‘° ν•΄μ œ
      return result;
   }
   
   public boolean isEmpty()
   {
      return size == 0;
   }
   
   
   private void ensureCapacity()
   {
      if (elements.length == 0) {
         elements = Arrays.copyOf(elements, 2 * size + 1);
      }
   }
   
   public static void main(String[] args)
   {
      Stack<String> stack = new Stack<>();
      for (String arg : List.of("a", "b", "c"))
      {
         stack.push(arg);
      }
      while (stack.isEmpty())
      {
         System.out.println(stack.pop().toUpperCase());
      }
   }
}

 

μ œλ„€λ¦­ λ°°μ—΄ 생성 였λ₯˜λ₯Ό ν•΄κ²°ν•˜λŠ” λ‘λ²ˆμ§Έ 방법은 elements ν•„λ“œμ˜ νƒ€μž…μ„ E[] μ—μ„œ Object[]둜 λ°”κΎΈλŠ” 것이닀. 

public E pop()
{
   if (size == 0) {
      throw new EmptyStackException();
   }

   // pushμ—μ„œ E νƒ€μž…λ§Œ ν—ˆμš©ν•˜λ―€λ‘œ 이 ν˜•λ³€ν™˜μ€ μ•ˆμ „ν•˜λ‹€.
   @SuppressWarnings("unchecked")
   E result = (E) elements[--size];
   elements[size] = null; // λ‹€ μ“΄ μ°Έμ‘° ν•΄μ œ
   return result;
}

이제 elements λ₯Ό κΊΌλ‚Ό λ•Œ μ›μ†Œμ— E둜 ν˜•λ³€ν™˜ν•˜λ©΄ 였λ₯˜ λŒ€μ‹  κ²½κ³ κ°€ λœ¨λŠ”λ° 

EλŠ” μ—­μ‹œ 싀체화 λΆˆκ°€ νƒ€μž…μ΄λ―€λ‘œ μ»΄νŒŒμΌλŸ¬λŠ” λŸ°νƒ€μž„μ— μ΄λ€„μ§€λŠ” ν˜•λ³€ν™˜μ΄ μ•ˆμ „ν•œμ§€ 증λͺ…ν•  방법이 μ—†λ‹€. 

ν•˜μ§€λ§Œ μš°λ¦¬λŠ” 직접 μ•ˆμ „ν•œμ§€ 증λͺ…ν•˜κ³  κ²½κ³ λ₯Ό 숨길 수 μžˆλ‹€. 

pop λ©”μ„œλ“œ 전체에 κ²½κ³ λ₯Ό μˆ¨κΈ°μ§€ 말고 λ²”μœ„λ₯Ό μ΅œμ†Œν™”ν•΄μ„œ ν˜•λ³€ν™˜μ„ μˆ˜ν–‰ν•˜λŠ” ν• λ‹Ήλ¬Έμ—λ§Œ μ–΄λ…Έν…Œμ΄μ…˜μ„ λΆ™μ—¬ κ²½κ³ λ₯Ό μˆ¨κ²Όλ‹€. 

 

 

 

🚩 μœ„μ—μ„œ μ–ΈκΈ‰ν•œ μ œλ„€λ¦­ λ°°μ—΄ 생성을 μ œκ±°ν•˜λŠ” 두 방법 λͺ¨λ‘ λ‚˜λ¦„μ˜ 지지λ₯Ό μ–»κ³  μžˆλ‹€. 

첫번째 방법인 Object 배열을 μƒμ„±ν•œ 뒀에 μ œλ„€λ¦­ λ°°μ—΄λ‘œ ν˜•λ³€ν™˜ ν•˜λŠ” 방법은 가독성이 μ’‹κ³ , ν˜•λ³€ν™˜μ„ λ°°μ—΄ μƒμ„±μ‹œ ν•œ 번만 ν•œλ‹€λŠ” μž₯점이 있으며, μ½”λ“œλ„ 짧닀. 

λ‘λ²ˆμ§Έ 방법인 μ œλ„€λ¦­ λ°°μ—΄ λŒ€μ‹ μ— Object 배열을 μ‚¬μš©ν•˜κ³ , 배열이 λ°˜ν™˜ν•œ μ›μ†Œλ₯Ό E둜 ν˜•λ³€ν™˜ν•˜λŠ” 방법은 λ°°μ—΄μ—μ„œ μ›μ†Œλ₯Ό 읽을 λ•Œ λ§ˆλ‹€ ν˜•λ³€ν™˜μ„ ν•΄μ€˜μ•Ό ν•œλ‹€. 

λ”°λΌμ„œ ν˜„μ—…μ—μ„œλŠ” 첫번째 방법을 더 μ„ ν˜Έν•˜λ©° 자주 μ‚¬μš©ν•˜λŠ” νŽΈμ΄λ‹€. 

 

그런데 첫번째 방법은 Eκ°€ Objectκ°€ μ•„λ‹Œν•œ λŸ°νƒ€μž„ νƒ€μž…μ΄ 컴파일 νƒ€μž…κ³Ό λ‹¬λΌμ„œ νž™ μ˜€μ—Ό heap pollution을 λ°œμƒν•  수 μžˆλ‹€. 

νž™ μ˜€μ—Όμ΄ κ±Έλ¦¬λŠ” μ‚¬λžŒμ€ λ‘λ²ˆμ§Έ 방식을 μ‚¬μš©ν•˜κΈ°λ„ ν•œλ‹€. 

 

 

 

 

πŸ“š 정리

ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ 직접 ν˜•λ³€ν™˜ν•΄μ•Ό ν•˜λŠ” νƒ€μž…λ³΄λ‹€ μ œλ„€λ¦­ νƒ€μž…μ΄ 더 μ•ˆμ „ν•˜κ³  μ“°κΈ° νŽΈν•˜λ‹€. 

λ”°λΌμ„œ μƒˆλ‘œμš΄ νƒ€μž…μ„ 섀계할 λ•ŒλŠ” ν˜•λ³€ν™˜ 없이도 μ‚¬μš©ν•  수 μžˆλ„λ‘ μ œλ„€λ¦­ νƒ€μž…μœΌλ‘œ λ§Œλ“€μž!!

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90